Tailwind를 떠나 CSS 구조화를 배우기
원문은 Julia Evans님이 에 게재했습니다. 이 블로그 구독하기
안녕하세요! 8년 전 저는 Tailwind를 발견한 이야기를 신나게 썼습니다.
그때 저는 CSS 코드를 어떻게 구조화해야 할지 전혀 감이 없었고, 완전한 혼돈과 Tailwind 중 하나를 골라야 한다면 기꺼이 Tailwind를 선택했습니다. 정말 만족스러운 선택이었고, 덕분에 작은 사이트들을 많이 만들 수 있었죠!
지난 한 주 정도 저는 몇 개의 사이트를 Tailwind에서 좀 더 시맨틱한 HTML과 바닐라 CSS로 옮기는 작업을 했는데, 정말 너무 재미있고 흥미로웠습니다. 그래서 배운 것들을 공유해보려고 합니다!
여느 때처럼 저는 풀타임 프론트엔드 개발자가 아니어서, CSS 공부는 여러 해에 걸쳐 띄엄띄엄 이루어졌습니다.
알고 보니 Tailwind가 내게 많은 걸 가르쳐줬다
CSS 구조화에 대해 고민하기 시작했을 때 처음엔 좀 겁이 났습니다. 저는 CSS를 구조화하는 걸 잘 못하니까요! 하지만 CSS 구조화에 대해 다룬 블로그 글들(예를 들면 A whole cascade of layers나 How I write CSS in 2024 같은 글)을 읽기 시작하면서 몇 가지를 깨닫게 됐습니다.
- 모든 CSS 코드베이스에는 여러 가지 관심사가 뒤섞여 있다(레이아웃! 폰트! 색상! 공통 컴포넌트!)
- 그 각각을 관리할 시스템이나 가이드라인이 있으면 매우 유용하고, 그렇지 않으면 혼란에 빠지기 쉽다
- Tailwind는 이 중 일부에 대한 시스템을 갖추고 있고, 나는 이미 그 시스템을 알고 있다! 마음에 드는 시스템은 따라 해 보면 되겠다!
예를 들어 Tailwind에는 이런 것들이 있습니다.
앞으로 다룰 시스템들
앞으로 제 CSS 코드베이스의 몇 가지 측면과, 각각에 어떤 규칙을 적용하고 싶은지에 대한 현재 생각을 이야기해보려고 합니다. 일부는 Tailwind에서 가져온 것이고 일부는 그렇지 않습니다.
- 리셋
- 컴포넌트
- 색상
- 폰트 크기
- 유틸리티 클래스
- 베이스
- 간격
- 반응형 디자인
- 빌드 시스템
1. 리셋
저는 그냥 Tailwind의 “preflight styles”를 tailwind.css에 들어가서 앞부분 200줄 정도를 복사해 왔습니다.
시간이 지나면서 Tailwind의 CSS 리셋과 나름 친숙해졌다는 걸 알게 됐습니다. 예를 들어 Tailwind는 모든 요소에 box-sizing: border-box를 설정합니다(요소의 너비에 패딩이 포함된다는 의미죠).
* { box-sizing: border-box; }이런 설정 없이 CSS를 작성하려면 꽤 적응이 필요할 것 같습니다. Tailwind 리셋에는 html {line-height: 1.5;} 같은 다른 것들도 많이 있는데, 저는 무의식적으로 익숙해져서 존재조차 인식하지 못하고 있을 겁니다.
2. 컴포넌트
다음 부분이 CSS의 대부분을 차지합니다!
여기서의 아이디어는 CSS를 “컴포넌트” 단위로 정리하는 것입니다. Vue나 React 컴포넌트와 정신적으로 통하는 방식이죠.(물론 사이트에 JavaScript가 전혀 없을 수도 있지만요)
기본적인 아이디어는 이렇습니다.
- 각 “컴포넌트”는 고유한 클래스를 갖는다
- 한 컴포넌트의 CSS가 다른 컴포넌트의 CSS를 절대 덮어쓰지 않는다
- 각 컴포넌트는 자신만의 CSS 파일을 갖는다
그래서 한 컴포넌트의 CSS를 수정해도 다른 컴포넌트의 무언가가 알 수 없는 이유로 고장 나는 일이 없습니다. 그리고 제가 실제로 수정하고 싶어 하는 CSS의 80% 정도는 여러 컴포넌트 파일에 들어 있으니, 100줄짜리 컴포넌트를 수정할 때는 그 100줄만 생각하면 됩니다. 저에게는 훨씬 생각하기가 쉽습니다.
예를 들어, 이 HTML이 .zine “컴포넌트”일 수 있습니다.
<figure class="zine horizontal">
<img src="whatever.jpg">
</figure>그리고 중첩 선택자를 사용한 CSS는 대략 이렇게 생겼습니다.
.zine {
...
&.horizontal {
...
}
&.vertical {
...
}
&:hover {
...
}
}웹 컴포넌트나 @scope 같은 방식으로 컴포넌트끼리 간섭하지 않도록 프로그래밍적으로 보장하는 조치는 아직 하지 않았습니다. 하지만 그냥 컨벤션을 정하고 최선을 다하는 것만으로도 이미 크게 개선된 느낌입니다.
다음은 사이트 전반의 일관성을 유지하고 이 컴포넌트들을 서로 조화롭게 유지하기 위한 컨벤션입니다!
3. 색상
colours.css에는 필요에 따라 사용할 수 있는 여러 변수가 이렇게 들어 있습니다. 색상은 정말 다루기 어렵고 이번 리팩터링에서 색상 사용을 다시 손보고 싶지 않아서 그대로 두었습니다.
여기서 제가 지키려고 하는 유일한 가이드라인은 사이트에서 사용하는 모든 색상을 이 파일에 모아둔다는 것입니다.
:root {
--pink: #fea0c2;
--pink-light: #F9B9B9;
--red: #f91a55;
--orange: rgb(222, 117, 31);
...
}4. 폰트 크기
Tailwind에서 좋았던 점 중 하나는 폰트 크기를 정할 때 “음, 텍스트를 크게 하고 싶네”라고 생각하고 그냥 text-lg라고 쓰면 끝이라는 것이었습니다! 혹시 충분히 크지 않으면 xl이나 2xl을 쓰면 되고요. em을 쓰는지 px를 쓰는지 rem을 쓰는지를 기억하려고 애쓸 필요가 없었죠.
그래서 저는 Tailwind에서 가져온 여러 변수를 이렇게 정의했습니다.
--size-xs: 0.75rem;
--line-height-xs: 1rem;
--size-sm: 0.875rem;
--line-height-sm: 1.25rem;그러면 폰트 크기를 설정하고 싶을 때 이렇게 할 수 있습니다. Tailwind보다는 조금 장황하지만 지금은 만족합니다.
h3 {
font-size: var(--size-lg);
line-height: var(--line-height-lg);
}5. 유틸리티
버튼처럼 여러 컴포넌트에 걸쳐 등장하는 것들이 있습니다. 저는 이런 것들을 “유틸리티”라고 부릅니다.
Tailwind에서 몇 가지 유틸리티 클래스를 가져왔습니다(예를 들어 스크린 리더 사용자에게만 보여줘야 하는 것들을 위한 .sr-only 같은 클래스).
이 섹션은 규모가 꽤 작고, 저는 여기서 변경을 할 때 신중하려고 합니다.
6. 베이스
“베이스” 스타일은 제가 직접 정해서 사이트 전반에 적용하는 스타일입니다. 사이트 전체에 많은 스타일을 강제할 자신이 없어서 이 섹션은 정말 작게 유지해야 합니다. 지금은 이 두 개만 괜찮다고 느끼고 있고, <section> 쪽은 바꿀 수도 있습니다.
/* put a 950px column in the middle of each <section> */
section {
--inner-width: 950px;
padding: 3rem max(1rem, (100% - var(--inner-width))/2);
}
a {
color: var(--orange);
}베이스 스타일은 상향식(bottom-up)으로 작업하는 게 저에게는 가장 쉬울 것 같습니다. 처음에는 베이스 스타일에 거의 아무것도 넣지 않고 시작했다가, 공통으로 필요한 것들을 파악하게 되면 컴포넌트의 스타일을 베이스 스타일로 옮기는 방식이죠.
7. 간격
패딩과 마진을 관리하는 방법은 아직 완전히 정립하지 못했습니다. 다만 Tailwind에서처럼 원하는 모양이 나올 때까지 여기저기 마구 패딩과 마진을 넣던 방식보다는 좀 더 원칙 있게 하려고 확실히 노력하고 있습니다.
지금은 가능한 한 바깥쪽 레이아웃 컴포넌트가 간격을 책임지도록 하려고 합니다. 예를 들어 자식 요소들 사이에 간격을 두고 싶은 <section>이 있다면, 이렇게 해서 자식들을 균등하게 배치할 수 있습니다.
section > *+* {
margin-top: 1rem;
}참고한 블로그 글들:
8. 반응형 디자인: grid를 더 활용하기!
Tailwind에서 제가 하던 반응형 디자인 방식은 미디어 쿼리를 많이 사용하는 것이었습니다. Tailwind에는 md:text-xl 같은 문법이 있는데, 이는 “md 크기 이상에서 text-xl 스타일을 적용하라”는 의미입니다.
지금은 꽤 다른 방식을 시도하고 있는데, 브레이크포인트를 많이 필요로 하지 않는 더 유연한 CSS grid 레이아웃을 만드는 것입니다. 어렵지만 grid로 무엇이 가능한지 배우는 과정이 정말 흥미롭고, Tailwind로는 불가능하다고 생각하는 것의 좋은 예이기도 합니다.
예를 들어, 큰 화면에서는 2열, 작은 화면에서는 1열을 자동으로 사용하도록 auto-fit을 쓰는 방법을 배우고 있습니다. 이렇게요.
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), max-content));
justify-content: center;저는 grid-template-areas도 많이 사용했는데, 정말 놀라운 기능이고 Tailwind로는 사용할 수 없다고 생각합니다.
참고 자료:
- A responsive grid layout with no media queries from CSS Tricks
9. 빌드 시스템: esbuild
개발 과정에서는 빌드 시스템이 필요하지 않습니다. CSS에는 이제 이런 식의 내장 import 문과
@import "reset.css";
@import "typography.css";
@import "colors.css";이런 식의 내장 중첩 선택자가 모두 있으니까요.
.page {
h2 { ...}
}원한다면 프로덕션용으로 esbuild를 사용해 CSS 파일을 번들링할 수 있습니다. 대략 이렇게 생겼습니다.
esbuild style.css --bundle --loader:.svg=dataurl --loader:.woff2=file --outfile=/tmp/out.css저는 보통 CSS와 JS 빌드 시스템 사용을 피하지만, esbuild는 웹 표준에 기반하고 정적 Go 바이너리이기 때문에 사용하는 데 거부감이 없습니다(2021년에 여기에 대해 쓴 적이 있습니다).
왜 Tailwind에서 떠나기로 했을까?
Tailwind에서 왜 떠나냐고 물어본 분들이 몇 있었습니다. 그 결정에 영향을 준 몇 가지 요인은 다음과 같습니다.
- Tailwind는 2018년 이후로 빌드 시스템에 훨씬 더 의존하게 됐습니다. 빌드 시스템 없이 최신 버전의 Tailwind를 사용하는 건 불가능한(?) 것 같습니다. 그래서 저는 수년 동안 Tailwind v2를 사용해 왔습니다.(litewind라는 것도 있다고 하더군요)
- 원래부터 Tailwind는 빌드 시스템과 함께 사용하도록 되어 있었지만, 저는 사실 그렇게 한 적이 없어서 많은 프로젝트에 2.8MB짜리
tailwind.min.css파일( gzip으로 압축하면 270K)이 있고, 좀 어색하게 느껴집니다. - Tailwind를 처음 쓰기 시작했을 때보다 CSS 실력이 훨씬 좋아졌다
- 궁극적으로 Tailwind는 제약이 많습니다. CSS로 뭔가 특이한 걸 하고 싶을 때 Tailwind로는 항상 가능한 게 아니죠. 그런 제약이 굉장히 유용할 수도 있지만(이 글의 상당 부분은 Tailwind의 제약을 제가 다시 구현하는 이야기입니다!) 지금 시점에서는 제가 골라서 선택할 수 있기를 바랍니다.
- 결국 같은 프로젝트 안에 바닐라 CSS와 Tailwind가 뒤섞인 사이트가 생겨버렸고, 유지보수하기가 전혀 즐겁지 않았다
- 좀 더 시맨틱한 HTML을 작성하는 게 어떤 느낌일지 궁금해졌다.
궁금한 CSS 기능들
이 작업을 하면서 저는 사용하지는 않았지만 언젠가 배워보고 싶은 CSS 기능들을 많이 알게 됐습니다.
@layer(from A Whole Cascade of Layers)- @scope) (especially this example of how to use @scope in a “component” CSS design from the specification!)
- container queries
- subgrid
Tailwind를 떠난 마지막 이유 한 가지
이 글에서 저는 Tailwind를 사용하면서 배운 점에 대해 많이 이야기했고, 그건 모두 사실입니다.
하지만 3년 전에 Tailwind and the Femininity of CSS라는 글을 읽었는데, 정말 마음에 오래 남았습니다. 솔직히 말하면 저는 처음에 그 글에서 묘사하는 것과 비슷한 태도로 CSS에 접근했던 것 같습니다.
그들은 CSS가 단순하다고 들었으니 쉽다고 생각한다. 하지만 실제로 써보면 잘 되지 않는다. 그러면 언어 탓이라고 생각하게 된다. 자신은 똑똑하다는 걸 알고 있고, 이건 쉬워야 한다고 들었으니까.
하지만 지난 10년 동안 저는 CSS라는 기술을 정말 사랑하고 존중하게 됐습니다.
그래서 저는 몇 년 전에 “CSS는 어렵다”는 말에 대해 CSS를 평가절하하는 대신, CSS를 더 잘하고 기술로서 진지하게 대하는 방식으로 대응하기로 결심했습니다. 그렇게 하니 모든 게 달라졌습니다. 저를 좌절하게 했던 많은 문제들(“가운데 정렬은 불가능해”)이 이미 오래전에 CSS에서 해결되었다는 걸 알게 됐고, 또 “가운데 정렬”이 무엇을 의미하는지 자체가 항상 명확하지 않으며 여러 방법이 있는 게 당연하다는 것도 알게 됐습니다. CSS가 어려운 이유는 어려운 문제를 풀고 있기 때문입니다!
지난 10~15년 동안 만들어진 새로운 CSS 기능들(이 글에서 이야기한 것들도 일부 포함됩니다!)과 그 기능들이 CSS 사용을 얼마나 쉽게 만드는지에 깊은 인상을 받았고, CSS 실력을 키우는 데 시간을 쓰는 것은 정말 멋진 경험이었습니다.
그리고 그 글은 Tailwind가 CSS 전문성을 평가절하하는 데 일조한다는 느낌을 주었고, Tailwind가 개인적으로는 유용한 도구였더라도 저는 그런 일에 동참하고 싶지 않다는 생각이 들었습니다. 특히 LLM 시대인 지금, 인간의 전문성을 소중히 여기는 것이 그 어느 때보다 중요하게 느껴집니다.
영향을 받은, Tailwind를 비판하는 또 다른 블로그 글:
일단은 여기까지!
wizardzines.com의 CSS를 처음 디자인하고 작성한 Melody Starling에게 감사드립니다. 사이트의 멋지고 재미있는 모든 것은 Melody 덕분입니다.
또 이 작업을 하면서 CSS Tricks, Smashing Magazine 등에서 CSS에 관한 놀라운 블로그 글들을 정말 많이 읽었습니다. 이 글 곳곳에서 그중 일부를 링크해 두었고, CSS 커뮤니티 분들이 자신의 노하우를 이렇게 많이 공유해 주시는 것에 정말 감사드립니다.
글을 무작위로 읽기
댓글
로그인하고 댓글 남기기