Tailwind CSS 4 완벽 가이드 — Oxide 엔진·CSS-first 설정·5배 빨라진 빌드

Tailwind CSS 4 완벽 가이드 — Oxide 엔진·CSS-first 설정·5배 빨라진 빌드

이 글의 핵심

Tailwind CSS 4는 Rust 기반 Oxide 엔진으로 재작성되어 빌드 속도가 Full 빌드 5배, Incremental 빌드 100배 이상 빨라진 메이저 릴리스입니다. `tailwind.config.js`가 사라지고 CSS 파일 안에서 `@theme`로 설계 토큰을 선언하며, 최신 CSS 기능(`@container`·`color-mix()`·3D transforms·로우레벨 variants)을 1급으로 지원합니다. 이 글은 새 설정 방식·새 유틸리티·마이그레이션을 실전 중심으로 정리합니다.

설치

Vite

pnpm add -D tailwindcss @tailwindcss/vite
// vite.config.ts
import { defineConfig } from "vite"
import tailwindcss from "@tailwindcss/vite"

export default defineConfig({
  plugins: [tailwindcss()],
})
/* src/styles.css */
@import "tailwindcss";

이게 전부입니다. tailwind.config.js·postcss.config.js 불필요.

PostCSS

pnpm add -D tailwindcss @tailwindcss/postcss postcss
// postcss.config.mjs
export default {
  plugins: { "@tailwindcss/postcss": {} },
}

Astro

pnpm add -D tailwindcss @tailwindcss/vite
// astro.config.mjs
import tailwindcss from "@tailwindcss/vite"
export default defineConfig({
  vite: { plugins: [tailwindcss()] },
})

CSS-first 설정: @theme

/* src/styles.css */
@import "tailwindcss";

@theme {
  --color-brand-50:  oklch(97% 0.02 250);
  --color-brand-500: oklch(55% 0.18 250);
  --color-brand-900: oklch(25% 0.12 250);

  --font-sans: "Inter Variable", ui-sans-serif, system-ui;
  --font-mono: "JetBrains Mono", ui-monospace;

  --radius-base: 0.5rem;

  --breakpoint-xl: 1280px;
  --breakpoint-2xl: 1536px;

  --spacing: 0.25rem;   /* 1 unit = 4px */
}
  • 자동으로 bg-brand-500·text-brand-900·font-sans·rounded-base 유틸 생성
  • --color-*·--font-*·--radius-*·--breakpoint-* 같은 규약 네임스페이스
  • OKLCH 색공간으로 균일한 색 그라디언트

기존 토큰 재정의

@theme {
  --color-gray-50:  oklch(98% 0 0);
  --color-gray-900: oklch(22% 0 0);
  --font-sans: "Pretendard Variable", ui-sans-serif;
}

토큰 비활성화

@theme {
  --color-red-*: initial;   /* red 팔레트 제거 */
}

@source: 스캔 대상

@import "tailwindcss";

@source "./src/**/*.{html,js,ts,tsx,astro}";
@source "../packages/ui/src/**/*.tsx";
  • v4는 자동 감지가 기본(현재 워크스페이스 스캔)
  • 추가 소스가 있으면 명시
  • @source not "..." 로 제외

@plugin

@plugin "@tailwindcss/typography";
@plugin "@tailwindcss/forms";
@plugin "./my-custom-plugin.js";

신 유틸리티 하이라이트

동적 값

v3에서 필요했던 safelist나 arbitrary value 입력 없이 동적 스페이싱:

<div class="w-136 h-72.5 gap-3.5 my-13">
<!-- 자동으로 136 × --spacing 등 계산 -->
  • w-*, h-*, p-*, m-*, gap-*, top-* 등 주요 수치 유틸이 임의 배수 허용

컨테이너 쿼리

<div class="@container">
  <div class="grid @md:grid-cols-2 @xl:grid-cols-4 gap-4">
    <!-- 부모 크기 기준 반응형 -->
  </div>
</div>

별도 플러그인 없이 기본 내장.

Color mixing

<div class="bg-brand-500/50">       <!-- 50% 투명도 -->
<div class="bg-[color-mix(in_oklch,theme(colors.brand.500),black_20%)]">

3D Transforms

<div class="rotate-x-45 rotate-y-12 perspective-dramatic transform-3d">
  3D card
</div>

gradient 각도·interpolation

<div class="bg-gradient-to-br from-cyan-500 to-blue-500 via-30% via-teal-500">
<div class="bg-linear-45 from-red-500 to-yellow-500 in-oklch">

Starting styles (entry 애니메이션)

<dialog class="@starting-style:opacity-0 @starting-style:scale-95 transition-all">
  ...
</dialog>

CSS @starting-style을 네이티브로 지원해 진입 애니메이션 작성이 쉬워짐.

Text wrap

<p class="text-balance">           <!-- 헤드라인 밸런스 -->
<p class="text-pretty">            <!-- 본문 자연스러움 -->

Variants 확장

<!-- 자식 & 이웃 -->
<ul>
  <li class="*:py-2 *:border-b *:last:border-0">...</li>
</ul>

<!-- group/name 다중 -->
<div class="group/card">
  <div class="group/inner">
    <p class="group-hover/card:text-brand-500 group-focus/inner:underline">...</p>
  </div>
</div>

<!-- has() -->
<label class="has-[input:checked]:bg-green-100">
  <input type="checkbox" /> Accept
</label>

<!-- not() -->
<button class="not-disabled:hover:bg-brand-500">

<!-- in-range / out-of-range (input) -->
<input class="in-range:border-green-500 out-of-range:border-red-500" type="number" min="0" max="100" />

Dark mode

@variant dark (&:where(.dark, .dark *));

또는 media 기반:

@variant dark (@media (prefers-color-scheme: dark));
<html class="dark">
  <body class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">

커스텀 유틸리티

@utility btn {
  @apply px-4 py-2 rounded-base font-medium;
}

@utility btn-primary {
  @apply btn bg-brand-500 text-white hover:bg-brand-900;
}

컴포넌트 클래스 정의가 훨씬 깔끔해졌습니다.

Layer 제어

@layer base {
  h1 { @apply text-3xl font-bold; }
}

@layer components {
  .card { @apply p-6 rounded-xl border; }
}

로우레벨 variants

완전히 커스텀 selector:

@variant theme-blue (html[data-theme="blue"] &);
@variant mobile (@media (max-width: 640px));
<div class="theme-blue:bg-blue-500 mobile:hidden">

마이그레이션 (v3 → v4)

npx @tailwindcss/upgrade@latest
  • 스캐너가 프로젝트를 분석해 자동 변환
  • tailwind.config.js → CSS @theme/@source
  • @tailwind base/components/utilities@import "tailwindcss"
  • Deprecated 유틸리티 자동 교체

수동 체크리스트:

  • 커스텀 플러그인 v4 호환 확인
  • safelist를 동적 유틸리티로 대체
  • container 유틸 API 변경(@container preferred)

성능 비교

공식 벤치마크:

  • Full build: v3 약 10초 → v4 약 2초 (5x)
  • Incremental build: v3 수백ms → v4 10-50ms (100x)
  • CSS 출력 크기: v3 대비 동등 또는 소폭 감소

이유:

  • Rust(Oxide) + Lightning CSS로 재작성
  • 파일 스캐닝·변환이 병렬화
  • PostCSS 파이프라인 오버헤드 제거

실전 예시: 카드 컴포넌트

<article class="@container group/card max-w-md mx-auto">
  <div class="p-6 rounded-2xl border border-gray-200 dark:border-gray-800
              bg-white dark:bg-gray-900 transition
              hover:shadow-lg hover:-translate-y-0.5
              has-[img:hover]:ring-2 ring-brand-500">

    <img src="..." class="w-full aspect-video object-cover rounded-xl mb-4
                          group-hover/card:brightness-110 transition" />

    <h2 class="text-xl font-semibold text-balance
               @md:text-2xl text-gray-900 dark:text-gray-50">
      Tailwind CSS v4로 쓴 카드
    </h2>

    <p class="mt-2 text-gray-600 dark:text-gray-300 text-pretty">
      컨테이너 쿼리·has·group 변형·다크 모드가 하나의 컴포넌트에 자연스럽게.
    </p>

    <div class="mt-4 flex items-center gap-3">
      <button class="btn-primary">Read</button>
      <button class="btn border border-gray-300 dark:border-gray-700
                     text-gray-700 dark:text-gray-300">
        Save
      </button>
    </div>
  </div>
</article>

프레임워크 통합

Next.js (App Router)

/* app/globals.css */
@import "tailwindcss";
@import "./design-tokens.css";

@theme {
  --font-sans: "Inter Variable", ui-sans-serif;
}
// app/layout.tsx
import "./globals.css"

Svelte / Vue

동일: Vite 플러그인 + CSS import.

shadcn/ui 통합

shadcn 컴포넌트는 v4 기반으로 재작성되었고 components.json + @theme로 토큰 관리됩니다. CLI도 v4 인식해 새 컴포넌트 추가 시 v4 문법의 코드를 생성.

트러블슈팅

클래스가 적용되지 않음

  • @source에 파일 경로 포함 여부 확인
  • 자동 스캔 범위 점검 (monorepo의 외부 패키지 사용 시)

JS config를 계속 쓰고 싶다

@config "./tailwind.config.js";

호환 모드 유지 가능.

HMR이 여전히 느림

  • @source 범위 너무 넓지 않은지
  • 플러그인 수 줄이기
  • Vite 캐시 삭제(--force)

Tailwind IntelliSense 제안 없음

  • v4 지원 버전(2024.12+)으로 업데이트
  • VS Code 설정에서 tailwindCSS.experimental.configFile 제거

dark variant 동작 안 함

  • @variant dark (...) 정의 확인
  • html에 class="dark" 또는 media 쿼리 매치

체크리스트

  • v4 설치 + Vite/PostCSS 플러그인
  • @theme로 토큰 선언
  • @source로 필요시 추가 경로
  • 동적 수치 유틸로 safelist 제거
  • 컨테이너 쿼리·has·group variant 활용
  • 다크 모드 variant 확정
  • shadcn/ui 등 UI 키트 v4 업데이트
  • 업그레이드 CLI로 자동 마이그레이션

마무리

Tailwind CSS 4는 “느리고 설정이 무거운 Tailwind”라는 마지막 약점을 제거한 업그레이드입니다. Oxide 엔진으로 체감 속도가 완전히 달라지고, CSS-first 설정이 Tailwind를 “CSS 확장” 그 자체로 만들어 OOP·설정·빌드에 대한 부담이 크게 줄었습니다. 컨테이너 쿼리·has()·starting-style 같은 최신 CSS가 1급으로 포함되어 디자인 시스템 수준의 UI 구축이 한결 쉬워졌고, shadcn/ui·Radix·Ark UI 같은 현대 컴포넌트 스택과의 궁합도 최상입니다. 지금 v3 프로젝트를 쓰고 있다면 @tailwindcss/upgrade 실행만으로 업그레이드의 과실을 즉시 수확할 수 있습니다.

관련 글

  • Tailwind CSS 완벽 가이드
  • 모던 CSS 기능 완벽 가이드
  • shadcn/ui 완벽 가이드
  • 디자인 토큰 완벽 가이드