(번역) Tailwind에서 벗어나기, 그리고 CSS 구조화 방법 배우기

TapK·2026년 5월 26일
post-thumbnail

원문: 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 학습은 모두 여러 해에 걸쳐 띄엄띄엄 이루어졌습니다.

알고 보니 Tailwind는 저에게 많은 것을 가르쳐 주었다

CSS 구조화에 대해 처음 생각하기 시작했을 때, 저는 좀 위축되었습니다. 저는 CSS 구조화를 잘 못하거든요! 하지만 CSS 구조화에 대한 블로그 글들(예: A whole cascade of layersHow I write CSS in 2024)을 읽기 시작하면서 몇 가지를 깨달았습니다.

  1. 모든 CSS 코드베이스에는 여러 가지 것들이 섞여 있습니다 (레이아웃! 폰트! 색상! 공통 컴포넌트!)
  2. 그것들을 관리할 시스템이나 가이드라인을 갖추는 것이 매우 유용합니다. 그렇지 않으면 혼돈에 빠지게 됩니다
  3. Tailwind에는 이런 것들 중 일부에 대한 시스템이 있고, 저는 이미 그 시스템들을 알고 있습니다! 제가 좋아하는 시스템들을 흉내 낼 수 있을지도 모르겠네요!

예를 들어, Tailwind에는 다음과 같은 것들이 있습니다.

이 글에서 다룰 시스템들

저의 CSS 코드베이스의 몇 가지 측면과, 각각에 대해 어떤 규칙을 적용하고 싶은지 지금까지 생각한 것들을 이야기하려고 합니다. 일부는 Tailwind에서 가져왔고 일부는 아닙니다.

  1. 리셋(reset)
  2. 컴포넌트(components)
  3. 색상(colours)
  4. 폰트 크기(font sizes)
  5. 유틸리티 클래스(utility classes)
  6. 베이스(the base)
  7. 간격(spacing)
  8. 반응형 디자인(responsive design)
  9. 빌드 시스템(the build system)

1. 리셋

저는 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;} 같이 무의식적으로 익숙해진, 있는지도 모르는 다른 많은 것들이 있을 거라고 확신합니다.

2. 컴포넌트

이 다음 부분이 CSS의 대부분을 차지합니다!

여기서 아이디어는 CSS를 "컴포넌트" 단위로 구조화하는 것입니다. 뷰나 리액트 컴포넌트와 정신적으로 통하는 방식이죠. (사실 사이트에 자바스크립트가 전혀 없을 수도 있습니다)

기본적인 아이디어는 다음과 같습니다.

  1. 각 "컴포넌트"는 고유한 클래스를 가집니다
  2. 한 컴포넌트의 CSS는 다른 컴포넌트의 CSS를 절대 덮어쓰지 않습니다
  3. 각 컴포넌트는 자체 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 같은)을 도입하지는 않았지만, 그냥 컨벤션을 두고 최선을 다하는 것만으로도 이미 큰 개선처럼 느껴집니다.

다음은 사이트 전반의 일관성을 유지하고 이러한 컴포넌트들을 서로 조화롭게 유지하기 위한 컨벤션입니다!

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);
}

베이스 스타일은 바텀업 방식으로 작업하는 것이 저에게 가장 쉬울 것 같습니다. 먼저 거의 아무것도 없는 베이스 스타일에서 시작해서, 공통으로 적용하고 싶은 것들을 발견할 때마다 컴포넌트의 스타일 일부를 베이스 스타일로 옮기는 방식이죠.

7. 간격

패딩과 마진을 관리하는 접근법은 아직 완전히 정리하지 못했습니다. 하지만 Tailwind에서 했던 방식보다는 더 원칙적으로 하려고 노력하는 중입니다. Tailwind를 쓸 때는 그냥 원하는 모양이 나올 때까지 패딩과 마진을 아무렇게나 여기저기 넣었거든요.

지금은 가능한 한 바깥쪽 레이아웃 컴포넌트가 간격을 담당하도록 만들고 있습니다. 예를 들어 자식 요소들 사이에 간격을 두고 싶은 <section>이 있다면, 자식들 사이에 간격을 균등하게 두기 위해 다음과 같이 할 수 있습니다.

section > * + * {
  margin-top: 1rem;
}

영감을 받은 블로그 글들입니다.

8. 반응형 디자인 — 그리드를 더 많이 쓰자!

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에서는 사용할 수 없는 것 같습니다.

영감이 된 글입니다.

9. 빌드 시스템 — esbuild

개발 중에는 빌드 시스템이 필요 없습니다. 이제 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에서 벗어나는지 물어보셨습니다. 영향을 준 몇 가지 요인은 다음과 같습니다.

  • Tailwind는 2018년 이후로 빌드 시스템에 훨씬 더 의존하게 되었습니다. 새 버전의 Tailwind를 빌드 시스템 없이 사용하는 건 불가능한 것 같아요(?). 그래서 저는 몇 년 동안 Tailwind v2를 사용해왔습니다. (또 litewind 같은 것도 있다고 합니다)
  • Tailwind는 빌드 시스템과 함께 사용하는 것이 원래 의도이지만, 저는 그렇게 한 적이 없습니다. 그래서 많은 프로젝트에 2.8MB짜리 tailwind.min.css 파일(gzip으로 270K)이 들어 있는데, 이게 좀 어리석게 느껴집니다.
  • Tailwind를 처음 쓰기 시작했을 때보다 CSS를 훨씬 잘하게 되었습니다
  • 궁극적으로 Tailwind에는 한계가 있습니다. CSS에서 이상한 것(Weird Stuff)을 하고 싶을 때 Tailwind로는 항상 가능한 것은 아닙니다. 이런 한계는 매우 유용할 수 있습니다 (이 글의 많은 부분이 Tailwind의 한계 일부를 다시 구현하는 것에 관한 것입니다!). 하지만 지금 시점에서는 그것들을 골라서 쓸 수 있으면 좋겠습니다.
  • 같은 프로젝트 안에서 바닐라 CSS와 Tailwind를 섞은 사이트들이 만들어졌고, 유지 보수하기가 즐겁지 않았습니다
  • 더 시맨틱한 HTML을 작성하면 어떤 느낌일지 궁금해졌습니다.

궁금한 CSS 기능들

이번 작업을 하면서 사용하지는 않았지만 언젠가 배워보고 싶은 CSS 기능들을 많이 알게 되었습니다.

Tailwind에서 벗어난 마지막 이유

이 글에서 저는 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 커뮤니티 사람들이 자신의 실천을 얼마나 많이 공유하는지 정말 감사하게 생각합니다.

profile
누구나 읽기 편한 글을 위해

1개의 댓글

comment-user-thumbnail
7일 전

분문 글에서 지적한 용량 이슈나 최신 그리드 기능 지원 등의 한계는 최신 버전에서 모두 직관적으로 다룰 수 있도록 발전한 상태입니다.

혹여나 이 글을 읽는 다른 분들이 현재 버전의 문제점으로 오해하지 않으셨으면 하는 작은 바람이 있네요.

CSS가 조금 낯선 분들이라면 Tailwind을 이용하시면서 스타일을 어떻게 다루고 추상화하는지 브라우저 검사를 통해 공부하면 최신 CSS 실력을 정말 빠르게 키울 수 있습니다.

Tailwind에서 벗어나려는 부분에서 공감되는 부분이 있어 댓글 남겨봅니다.

번역 감사합니다.

답글 달기