
원문: https://jvns.ca/blog/2026/05/15/moving-away-from-tailwind--and-learning-to-structure-my-css-/
안녕하세요! 8년 전, 저는 Tailwind를 발견하고 신나서 글을 썼습니다.
당시 저는 CSS 코드를 어떻게 구조화해야 할지 전혀 몰랐고, 완전한 혼돈과 Tailwind 사이에서 선택해야 한다면 Tailwind를 정말 기쁘게 선택했습니다. Tailwind 덕분에 작은 사이트들을 많이 만들 수 있었거든요!
지난 일주일 정도 동안 몇 개의 사이트를 Tailwind에서 시맨틱 HTML과 바닐라 CSS로 마이그레이션했는데, 정말 재미있고 흥미로웠습니다. 그래서 그 과정에서 배운 몇 가지를 공유하려고 합니다!
평소처럼 저는 풀타임 프런트엔드 개발자가 아니라서, 제 CSS 학습은 모두 여러 해에 걸쳐 띄엄띄엄 이루어졌습니다.
CSS 구조화에 대해 처음 생각하기 시작했을 때, 저는 좀 위축되었습니다. 저는 CSS 구조화를 잘 못하거든요! 하지만 CSS 구조화에 대한 블로그 글들(예: A whole cascade of layers나 How I write CSS in 2024)을 읽기 시작하면서 몇 가지를 깨달았습니다.
예를 들어, Tailwind에는 다음과 같은 것들이 있습니다.
저의 CSS 코드베이스의 몇 가지 측면과, 각각에 대해 어떤 규칙을 적용하고 싶은지 지금까지 생각한 것들을 이야기하려고 합니다. 일부는 Tailwind에서 가져왔고 일부는 아닙니다.
저는 tailwind.css에 들어가서 처음 200줄 정도를 복사해 Tailwind의 "preflight styles"를 그대로 가져왔습니다.
시간이 지나면서 Tailwind의 CSS 리셋과 일종의 관계를 형성했다는 것을 깨달았습니다. 예를 들어 Tailwind는 모든 요소에 box-sizing: border-box를 설정합니다 (이는 요소의 width가 padding을 포함한다는 의미입니다).
* {
box-sizing: border-box;
}
이런 것들 없이 CSS를 작성하는 것은 저에게 정말 큰 적응 과정이 될 것 같고, Tailwind 리셋에는 html {line-height: 1.5;} 같이 무의식적으로 익숙해진, 있는지도 모르는 다른 많은 것들이 있을 거라고 확신합니다.
이 다음 부분이 CSS의 대부분을 차지합니다!
여기서 아이디어는 CSS를 "컴포넌트" 단위로 구조화하는 것입니다. 뷰나 리액트 컴포넌트와 정신적으로 통하는 방식이죠. (사실 사이트에 자바스크립트가 전혀 없을 수도 있습니다)
기본적인 아이디어는 다음과 같습니다.
그래서 한 컴포넌트의 CSS를 편집해도 다른 컴포넌트의 무언가가 알 수 없는 이유로 깨지지 않습니다. 그리고 제가 실제로 변경하고 싶은 CSS의 80% 정도는 여러 컴포넌트 파일에 있기 때문에, 100줄짜리 컴포넌트를 편집할 때는 그 100줄만 생각하면 됩니다. 저에게는 훨씬 더 생각하기 쉽습니다.
예를 들어, 이 HTML은 .zine "컴포넌트"가 될 수 있습니다.
<figure class="zine horizontal">
<img src="whatever.jpg">
</figure>
그리고 CSS는 중첩 선택자(nested selectors)를 사용해 다음과 같은 모습이 됩니다.
.zine {
...
&.horizontal {
...
}
&.vertical {
...
}
&:hover {
...
}
}
컴포넌트들이 서로 간섭하지 않도록 보장하는 프로그래밍적인 방법(웹 컴포넌트나 @scope 같은)을 도입하지는 않았지만, 그냥 컨벤션을 두고 최선을 다하는 것만으로도 이미 큰 개선처럼 느껴집니다.
다음은 사이트 전반의 일관성을 유지하고 이러한 컴포넌트들을 서로 조화롭게 유지하기 위한 컨벤션입니다!
colours.css에는 다음과 같은 변수들이 잔뜩 있고, 필요할 때마다 사용할 수 있습니다. 색상은 정말 어렵고, 이번 리팩터링에서 색상 사용을 다시 살펴보고 싶지 않아서 이 부분은 그대로 두었습니다.
여기서 강제하려는 유일한 가이드라인은 사이트에서 사용되는 모든 색상이 이 파일에 나열되어야 한다는 것입니다.
:root {
--pink: #fea0c2;
--pink-light: #F9B9B9;
--red: #f91a55;
--orange: rgb(222, 117, 31);
...
}
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);
}
여러 컴포넌트에 걸쳐 등장하는 버튼 같은 것들이 있습니다. 저는 이것들을 "유틸리티"라고 부르고 있습니다.
Tailwind에서 일부 유틸리티 클래스를 복사해왔습니다 (예: 스크린리더 사용자에게만 표시되어야 하는 것들을 위한 .sr-only).
이 섹션은 꽤 작고, 여기를 변경할 때는 조심하려고 합니다.
"베이스" 스타일은 제가 직접 선택해서 사이트 전체에 적용되는 스타일들입니다. 사이트 전체에 많은 스타일을 강제할 만큼 자신감이 없기 때문에 이 섹션은 정말 작게 유지해야 합니다. 지금 편하게 사용하고 있는 것은 이 두 가지뿐이고, <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);
}
베이스 스타일은 바텀업 방식으로 작업하는 것이 저에게 가장 쉬울 것 같습니다. 먼저 거의 아무것도 없는 베이스 스타일에서 시작해서, 공통으로 적용하고 싶은 것들을 발견할 때마다 컴포넌트의 스타일 일부를 베이스 스타일로 옮기는 방식이죠.
패딩과 마진을 관리하는 접근법은 아직 완전히 정리하지 못했습니다. 하지만 Tailwind에서 했던 방식보다는 더 원칙적으로 하려고 노력하는 중입니다. Tailwind를 쓸 때는 그냥 원하는 모양이 나올 때까지 패딩과 마진을 아무렇게나 여기저기 넣었거든요.
지금은 가능한 한 바깥쪽 레이아웃 컴포넌트가 간격을 담당하도록 만들고 있습니다. 예를 들어 자식 요소들 사이에 간격을 두고 싶은 <section>이 있다면, 자식들 사이에 간격을 균등하게 두기 위해 다음과 같이 할 수 있습니다.
section > * + * {
margin-top: 1rem;
}
영감을 받은 블로그 글들입니다.
Tailwind에서 제가 반응형 디자인을 했던 방식은 미디어 쿼리를 많이 쓰는 것이었습니다. Tailwind에는 md:text-xl이라는 구문이 있는데, "md 이상의 크기에서 text-xl 스타일을 적용한다"는 의미입니다.
지금은 꽤 다른 방식을 시도하고 있습니다. 브레이크포인트가 많이 필요하지 않은 유연한 CSS 그리드 레이아웃을 만드는 것이죠. 어렵지만, 그리드로 무엇이 가능한지 배우는 일은 정말 흥미롭고, 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에서는 사용할 수 없는 것 같습니다.
영감이 된 글입니다.
개발 중에는 빌드 시스템이 필요 없습니다. 이제 CSS에는 다음과 같이 내장 import 문이 있고,
@import "reset.css";
@import "typography.css";
@import "colors.css";
다음과 같이 내장 중첩 선택자도 있습니다.
.page {
h2 { ...}
}
원한다면 프로덕션용으로 CSS 파일을 번들링하기 위해 esbuild를 사용할 수 있습니다. 다음과 같은 식입니다.
esbuild style.css --bundle --loader:.svg=dataurl --loader:.woff2=file --outfile=/tmp/out.css
평소에는 CSS와 JS 빌드 시스템을 사용하지 않으려고 하지만, esbuild는 사용해도 괜찮다고 생각합니다(2021년에 여기에서 글을 썼습니다). 웹 표준을 기반으로 하고 정적 Go 바이너리이기 때문이죠.
몇몇 분들이 왜 Tailwind에서 벗어나는지 물어보셨습니다. 영향을 준 몇 가지 요인은 다음과 같습니다.
tailwind.min.css 파일(gzip으로 270K)이 들어 있는데, 이게 좀 어리석게 느껴집니다.이번 작업을 하면서 사용하지는 않았지만 언젠가 배워보고 싶은 CSS 기능들을 많이 알게 되었습니다.
@layer (A Whole Cascade of Layers에서)이 글에서 저는 Tailwind에서 배운 것에 대해 많이 이야기했고, 그건 모두 사실입니다.
하지만 3년 전에 Tailwind and the Femininity of CSS라는 글을 읽었는데, 그 글이 정말 마음에 남았습니다. 솔직히 저도 그 글에서 묘사하는 것과 비슷한 태도로 CSS를 시작했을 거예요.
그들은 CSS가 간단하다고 들었기 때문에 쉽다고 가정합니다. 하지만 막상 사용해 보면 원하는 대로 되지 않습니다.
그러나 지난 10년 동안 저는 기술로서의 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가 조금 낯선 분들이라면 Tailwind을 이용하시면서 스타일을 어떻게 다루고 추상화하는지 브라우저 검사를 통해 공부하면 최신 CSS 실력을 정말 빠르게 키울 수 있습니다.
Tailwind에서 벗어나려는 부분에서 공감되는 부분이 있어 댓글 남겨봅니다.
번역 감사합니다.