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 변경(@containerpreferred)
성능 비교
공식 벤치마크:
- 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 완벽 가이드
- 디자인 토큰 완벽 가이드