03 — Tailwind CSS

한 줄 답: Tailwind는 “클래스를 합성해 컴포넌트를 만든다”Atomic CSS 사상의 가장 성공한 구현체다. v4(2025)는 CSS-first config·@utility·Oxide 엔진으로 JS 설정 파일을 없애고 빌드를 10배 빠르게 했다. CSS 캐스케이드를 회피하는 길에서 이용하는 길로 전환한 분기점.


Why — 왜 Atomic CSS인가

전통 CSS의 문제:

/* 컴포넌트별 클래스 → 컴포넌트 수만큼 CSS 증가 */
.card     { padding: 16px; background: white; border-radius: 8px; }
.notice   { padding: 16px; background: white; border-radius: 8px; }
.dialog   { padding: 16px; background: white; border-radius: 8px; }
/* 같은 4 속성이 3번 반복 */

Atomic CSS의 발상:

.p-4     { padding: 16px; }
.bg-white { background: white; }
.rounded { border-radius: 8px; }
<div class="p-4 bg-white rounded">card</div>
<div class="p-4 bg-white rounded">notice</div>
<div class="p-4 bg-white rounded">dialog</div>

효과:

  • CSS는 유틸리티 N개에서 멈춘다 (선형 증가 → 상한).
  • HTML이 길어지지만 CSS는 짧아진다.
  • 컴포넌트마다 이름을 짓지 않아도 된다 (BEM의 인지 부하 해소).
  • 디자인 토큰을 강제한다 (p-4는 4*4px=16px로 고정 → 임의 값 못 씀).

How — Tailwind의 동작 원리

JIT(Just-In-Time) 엔진 — v3.0(2021) 이후 기본

  • 소스 파일을 실시간 스캔해서 사용된 클래스만 추출.
  • 임의 값 지원: class="top-[117px]"top: 117px; 즉시 생성.
  • 빌드 시 수십 GB였던 가상 CSS가 수십 KB로 줄어듦.

Tailwind v4 (2025) — Oxide 엔진

  • Rust 기반 Oxide 엔진 — v3 대비 전체 빌드 ~10x, 증분 빌드 ~100x 빠름.
  • Zero-configtailwind.config.js 불필요.
  • CSS-first config — 설정을 CSS 파일에서 직접.
  • 자동 콘텐츠 감지.gitignore 기반.

What — v4의 CSS-first config

tailwind.config.js(JS) → app.css(CSS) 한 곳으로 통합.

v3 (JS config)

// tailwind.config.js
module.exports = {
  content: ['./src/**/*.{html,js}'],
  theme: {
    extend: {
      colors: { brand: '#2563eb' },
      spacing: { 18: '4.5rem' },
    },
  },
};

v4 (CSS config)

/* app.css */
@import "tailwindcss";
 
@theme {
  --color-brand: #2563eb;
  --spacing-18: 4.5rem;
  --font-display: "Inter Display", sans-serif;
}

효과:

  • 토큰이 순수 CSS 변수로 출력 → 런타임에서도 var(--color-brand)로 사용 가능.
  • DevTools에서 바로 확인.
  • JS 빌드 도구 없이도 동작 (Vite/Webpack/CDN 모두).

What — v4의 @utility (커스텀 유틸리티)

이전엔 @layer utilities로 추가했는데, v4는 전용 디렉티브.

@utility tab-4 {
  tab-size: 4;
}
 
@utility scrollbar-hide {
  &::-webkit-scrollbar { display: none; }
  -ms-overflow-style: none;
  scrollbar-width: none;
}
<pre class="tab-4">...</pre>
<div class="scrollbar-hide">...</div>

장점:

  • Variant (hover:, md:) 자동 적용.
  • 빌드 타임에 정상 tree-shake.

What — Variants 시스템

Tailwind의 핵심 표현력은 클래스에 조건을 붙이는 variant.

Variant예시의미
상태hover:bg-blue-600:hover
포커스focus-visible:ring-2:focus-visible
반응형md:flex@media (width >= 768px)
다크모드dark:bg-gray-900@media (prefers-color-scheme: dark) 또는 .dark &
자식[&>p]:mt-2& > p
그룹group-hover:opacity-100부모에 .group
컨테이너 쿼리@md:flexcontainer query (v4)
:has()has-[input:invalid]:border-red-500:has()
@starting-stylestarting:opacity-0(v4)

조합:

<button class="bg-blue-500 hover:bg-blue-600 md:px-6 dark:bg-blue-700">

하나의 HTML 클래스 속성에 6가지 분기를 표현. 같은 일을 BEM으로 하면 btn btn--primary btn--md btn--dark btn--hovering ... 식의 modifier 폭주.


What — @apply (컴포넌트화)

긴 유틸 합성을 컴포넌트 클래스로 묶고 싶을 때.

.btn-primary {
  @apply px-4 py-2 rounded bg-blue-500 text-white hover:bg-blue-600;
}
<button class="btn-primary">Save</button>

언제 쓰나:

  • 같은 합성을 서버 렌더 HTML(템플릿)에서 반복 → @apply로 묶기.
  • 디자인 시스템 공용 컴포넌트 정의.

언제 쓰지 마라:

  • React/Vue 컴포넌트가 이미 컴포넌트 추상화를 한다 → <Button /> 안에서 클래스 합성하면 됨.
  • @apply 남발은 유틸리티-퍼스트의 장점을 무효화.

What — Tailwind v4의 @layer 통합

v4는 모든 Tailwind CSS를 *명시적 @layer*로 감싼다.

@layer theme, base, components, utilities;
 
@layer base { /* preflight (reset) */ }
@layer components { /* @apply로 만든 클래스 */ }
@layer utilities { /* px-4, bg-blue-500 등 */ }

→ 사용자가 비-Tailwind CSS를 자유롭게 끼워도 utilities가 항상 이긴다 (layer 순서 덕분). !important 거의 불필요.


What-if — Tailwind의 함정

1) 클래스 길이 폭주

<button class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2">
  Save
</button>

(이건 shadcn/ui의 실제 Button 클래스다.) HTML이 읽기 어려워진다.

해결:

  • React/Vue 컴포넌트로 클래스 합성을 캡슐화<Button variant="default" size="lg" />.
  • clsx/tailwind-variants조건부 결합 깔끔히.
  • 진짜 자주 반복되는 패턴만 @apply.

2) “Tailwind는 디자인 시스템을 대체하지 않는다”

<button class="bg-blue-500 text-white">A</button>
<button class="bg-blue-600 text-white">B</button>
<button class="bg-sky-500  text-white">C</button>

— 셋 다 비슷한 파란색 버튼인데 클래스가 다르다. Tailwind는 팔레트만 주지, 의미는 안 준다. semantic-token + @theme 으로 한 번 더 추상화해야 함:

@theme {
  --color-action-primary: theme(--color-blue-500);
}
<button class="bg-action-primary text-white">A</button>

3) 임의 값(arbitrary values) 남발

<div class="w-[473px] mt-[19px] text-[#2a3b4c]">

— 토큰 시스템 무시. 디자인 시스템의 의미가 사라짐. 임의 값은 토큰화의 마지막 수단이어야.

4) tailwind.config.js(v3) 비대화

v3 시절 거대한 theme.extend 객체에 수천 줄. v4는 CSS-first로 분리·import 가능해 해소.

5) Tailwind만으로 복잡한 애니메이션 시도

<div class="transition-all duration-300 ease-out hover:scale-110 hover:rotate-12 ...">

— 3D 트랜스폼·스프링·시퀀스 애니메이션은 Framer Motion/View Transitions API가 적합. Tailwind는 간단한 트랜지션만.


What-if — Tailwind를 어떤 프로젝트에서 쓰면 안 되나

상황권장
정적 마케팅 사이트, 1인 개발Tailwind 적합
대규모 디자인 시스템 (Figma + Storybook + 50명)Tailwind + 의미 토큰 레이어
Email HTML인라인 스타일 필요 — Tailwind 부적합
라이브러리 (npm 패키지)CSS Modules 또는 CSS-in-JS — 소비자의 Tailwind와 충돌 위험
Web Components / Shadow DOMShadow root에 Tailwind가 안 들어감 — 인라인 또는 CSS Modules
매우 동적인 스타일 (color: ${userColor})CSS Variables 또는 CSS-in-JS

Insight — Atomic CSS의 재림

Tailwind의 성공은 CSS의 패배가 아니라 모던 CSS의 승리 다.

2014년 Adam Wathan이 Tailwind를 만들기 전, 비슷한 시도들이 있었다:

  • 2011 Atomic CSS (Yahoo, Steve Souders)
  • 2014 BASSCSS, Tachyons
  • 2016 Atomizer

이들은 모두 클래스를 합성해 컴포넌트를 만든다는 사상이었지만 두 가지 한계가 있었다:

  1. 클래스 수가 폭발한다 → 빌드된 CSS가 수 MB.
  2. 임의 값 불가top: 117px이 안 됨.

2021년 Tailwind v3의 JIT 엔진이 두 한계를 동시에 해결했다 — 소스 코드를 실시간 스캔쓰인 것만 생성, 임의 값도 바로 컴파일. 완벽한 tree-shake.

흥미로운 점은 Tailwind v4가 모던 CSS의 결과물이라는 것이다:

  • v4의 @layer 통합은 CSS Cascade 5(2022) 가 가능케 했다.
  • @theme 디렉티브는 CSS Custom Properties + @property 위에 서 있다.
  • @utilityCSS Nesting(2023) 위에 서 있다.

CSS 자체가 언어로 충분히 발전했기 때문에, Tailwind는 얇은 어댑터가 될 수 있었다. v4의 출력 CSS를 보면 거의 순수 모던 CSS다.

Adam Wathan은 v4 발표에서 “Tailwind v4는 가능한 한 적게 우리가 만들고, 가능한 한 많이 CSS 자체가 하도록 했다” 고 했다. 도구가 얇아지는 것 — 그게 언어가 두꺼워졌다는 신호다.

Atomic CSS의 재림은 단순한 트렌드 회귀가 아니다. 모던 CSS가 따라잡은 결과 — 캐스케이드 회피가 아니라 이용하는 길이 열렸기 때문이다.


요약 + Mermaid

  • Tailwind는 OOCSS의 극단 — 클래스 1개 = 속성 1개.
  • JIT(v3)로 빌드 폭발 문제 해결, 임의 값 지원.
  • v4(2025): Oxide(Rust) 엔진, CSS-first config, @utility, @layer 통합.
  • **@apply**는 컴포넌트화 도구 — 적게 쓰는 게 정답.
  • 함정: 클래스 폭주, 의미 부재, 임의 값 남발.
  • 해결: 컴포넌트로 캡슐화 + 의미 토큰 레이어 + 디자인 시스템.

다음: 04-css-modules — 빌드 타임 스코핑의 또 다른 길.