CSS를 작성하는 방식에는 여러 철학이 있지만, 최근 몇 년간 Tailwind CSS는 가장 빠르게 성장한 방식 중 하나로 자리잡았습니다. "HTML에 클래스를 너무 많이 쓰는 거 아닌가?"라는 초기 거부감을 넘어서면, 놀라운 개발 속도와 일관된 디자인 시스템을 경험할 수 있습니다. 이 글에서는 Tailwind의 핵심 개념부터 실전 패턴까지 단계별로 살펴봅니다.

유틸리티 우선이란 무엇인가

전통적인 CSS 방식은 컴포넌트별 클래스를 만들고 스타일을 별도 파일에 정의합니다. Tailwind는 반대로, 각각의 CSS 속성을 담당하는 작은 클래스들을 조합해서 스타일을 만듭니다.

<!-- 전통적 BEM 방식 -->
<button class="btn btn--primary btn--lg">저장</button>

<!-- Tailwind 유틸리티 방식 -->
<button class="bg-blue-600 hover:bg-blue-700 text-white font-semibold
               px-6 py-3 rounded-lg transition-colors cursor-pointer">
  저장
</button>

처음엔 클래스가 많아 보이지만, CSS 파일을 따로 열어볼 필요 없이 HTML만 보면 스타일을 즉시 파악할 수 있습니다. 또한 사용된 클래스만 최종 CSS에 포함되므로 프로덕션 번들은 수 KB에 불과합니다.

설치 및 기본 설정

# npm
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

# tailwind.config.js
module.exports = {
  content: ['./src/**/*.{html,js,jsx,ts,tsx}'],
  theme: {
    extend: {},
  },
  plugins: [],
};
/* src/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

핵심 유틸리티 클래스

Tailwind의 클래스명은 CSS 속성을 직관적으로 표현합니다. 자주 쓰는 패턴을 익히면 나머지는 공식 문서를 검색해서 바로 쓸 수 있습니다.

<!-- 레이아웃 (Flexbox) -->
<div class="flex items-center justify-between gap-4">
  <span>왼쪽</span>
  <span>오른쪽</span>
</div>

<!-- 레이아웃 (Grid) -->
<div class="grid grid-cols-3 gap-6">
  <div class="col-span-2">메인 콘텐츠</div>
  <div>사이드바</div>
</div>

<!-- 타이포그래피 -->
<h1 class="text-3xl font-bold tracking-tight text-gray-900">제목</h1>
<p class="text-base text-gray-600 leading-relaxed">본문</p>

<!-- 간격 (Spacing: m=margin, p=padding, t/r/b/l/x/y) -->
<div class="mt-8 px-4 py-6 mb-2">...</div>

<!-- 테두리와 그림자 -->
<div class="border border-gray-200 rounded-xl shadow-md p-6">카드</div>

반응형 디자인 — 모바일 우선

Tailwind의 반응형은 클래스 앞에 브레이크포인트 접두사를 붙이는 방식입니다. 접두사 없는 클래스는 모든 크기에 적용되고, 접두사가 있으면 해당 크기 이상에서 적용됩니다.

<!-- 기본(모바일): 1열 / md(768px~): 2열 / lg(1024px~): 3열 -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
  ...
</div>

<!-- 텍스트 크기도 반응형으로 -->
<h1 class="text-2xl md:text-4xl lg:text-5xl font-bold">
  반응형 제목
</h1>

<!-- 모바일에서만 숨기기 -->
<nav class="hidden md:block">데스크톱 네비게이션</nav>
<button class="md:hidden">모바일 햄버거 버튼</button>

다크모드

tailwind.config.js에서 darkMode: 'class'를 설정하면 dark: 접두사로 다크모드 스타일을 지정할 수 있습니다.

// tailwind.config.js
module.exports = {
  darkMode: 'class', // 'media'로 바꾸면 OS 설정 따라감
  // ...
};
<!-- html 또는 body에 'dark' 클래스 토글 -->
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
  <h1 class="text-2xl font-bold">제목</h1>
  <p class="text-gray-600 dark:text-gray-400">본문</p>
  <button class="bg-blue-600 hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-400
                 text-white px-4 py-2 rounded">
    버튼
  </button>
</div>

<script>
  // 다크모드 토글
  document.querySelector('#toggle').addEventListener('click', () => {
    document.documentElement.classList.toggle('dark');
  });
</script>

@apply — 반복 클래스 추상화

같은 클래스 조합을 여러 곳에 반복한다면 @apply로 컴포넌트 클래스를 만들 수 있습니다. 단, 남용하면 Tailwind의 장점이 사라지므로 적절히 사용하세요.

/* src/index.css */
@layer components {
  .btn {
    @apply inline-flex items-center justify-center px-4 py-2 rounded-lg
           font-medium transition-colors focus:outline-none focus:ring-2
           focus:ring-offset-2 cursor-pointer;
  }

  .btn-primary {
    @apply bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500;
  }

  .btn-secondary {
    @apply bg-white text-gray-700 border border-gray-300
           hover:bg-gray-50 focus:ring-gray-400;
  }

  .card {
    @apply bg-white dark:bg-gray-800 rounded-xl border border-gray-200
           dark:border-gray-700 shadow-sm p-6;
  }
}

커스텀 디자인 토큰

tailwind.config.jstheme.extend에서 브랜드 색상, 폰트, 간격을 추가해 일관된 디자인 시스템을 만들 수 있습니다.

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      colors: {
        brand: {
          50:  '#f0f9ff',
          500: '#0ea5e9',
          600: '#0284c7',
          900: '#0c4a6e',
        },
      },
      fontFamily: {
        sans: ['Pretendard Variable', 'system-ui', 'sans-serif'],
      },
      spacing: {
        18: '4.5rem',
        88: '22rem',
      },
      borderRadius: {
        '4xl': '2rem',
      },
    },
  },
};

실전 카드 컴포넌트

앞서 배운 내용을 종합해 블로그 카드 컴포넌트를 만들어봅니다.

<article class="group bg-white dark:bg-gray-800 rounded-2xl border border-gray-200
                dark:border-gray-700 overflow-hidden shadow-sm hover:shadow-lg
                transition-shadow duration-300">
  <div class="aspect-video overflow-hidden">
    <img
      src="/post-image.jpg"
      alt="포스트 썸네일"
      class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
    />
  </div>
  <div class="p-6">
    <div class="flex gap-2 mb-3">
      <span class="text-xs font-medium bg-blue-100 dark:bg-blue-900 text-blue-700
                   dark:text-blue-300 px-2.5 py-1 rounded-full">CSS</span>
    </div>
    <h3 class="text-lg font-bold text-gray-900 dark:text-white mb-2
               group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors">
      카드 제목
    </h3>
    <p class="text-sm text-gray-600 dark:text-gray-400 leading-relaxed line-clamp-2">
      카드 설명이 들어갑니다. 두 줄로 자동 clamp됩니다.
    </p>
    <div class="flex items-center justify-between mt-4 pt-4 border-t
                border-gray-100 dark:border-gray-700">
      <span class="text-xs text-gray-500">2026. 04. 09</span>
      <a href="#" class="text-sm font-medium text-blue-600 hover:text-blue-700">
        자세히 보기 →
      </a>
    </div>
  </div>
</article>
Tailwind를 잘 쓰는 핵심 팁
1. VS Code Tailwind CSS IntelliSense 확장을 설치하면 자동완성과 호버 프리뷰를 쓸 수 있습니다.
2. prettier-plugin-tailwindcss로 클래스 순서를 자동 정렬하세요.
3. 반복되는 조합만 @apply로 추상화하고, 나머지는 HTML에 인라인으로 두는 것이 검색하기 쉽습니다.

JIT 모드와 동적 클래스 주의사항

Tailwind의 JIT(Just-In-Time) 컴파일러는 실제로 사용된 클래스만 번들에 포함합니다. 단, 동적으로 생성된 클래스 이름은 감지하지 못합니다.

// ❌ JIT가 감지 못함 — 빌드에서 제외될 수 있음
const color = 'red';
<div className={`text-${color}-500`}>

// ✅ 올바른 방법 — 완전한 클래스 이름 사용
const colorClass = condition ? 'text-red-500' : 'text-blue-500';
<div className={colorClass}>

동적 클래스 문제는 Tailwind 사용 중 가장 자주 겪는 함정입니다. CMS나 백엔드 API에서 색상값을 받아 동적으로 클래스를 생성하는 경우, tailwind.config.js의 safelist에 해당 클래스들을 명시적으로 추가해야 합니다.

Tailwind CSS v4 변경점

2025년 출시된 Tailwind CSS v4는 기존 버전과 크게 달라졌습니다. 설정 방식이 CSS 파일 중심으로 바뀌었고 빌드 속도가 대폭 개선됐습니다.

/* tailwind.css — v4에서는 CSS 파일에서 직접 설정 */
@import "tailwindcss";

/* 커스텀 테마 설정 (tailwind.config.js 불필요) */
@theme {
  --font-sans: 'Pretendard Variable', sans-serif;
  --color-brand: oklch(58% 0.22 264);
  --spacing-18: 4.5rem;
}

/* 커스텀 유틸리티 */
@utility card-shadow {
  box-shadow: 0 2px 8px oklch(0% 0 0 / 0.1);
}

v4에서는 tailwind.config.js 없이 CSS 파일 하나로 모든 설정을 관리합니다. Rust로 재작성된 빌드 엔진 덕분에 빌드 속도가 v3 대비 3~10배 빨라졌습니다.

Tailwind vs CSS Modules vs styled-components 비교

항목Tailwind CSSCSS Modulesstyled-components
번들 크기매우 작음 (사용한 것만)작음큼 (런타임 포함)
디자인 일관성높음 (토큰 기반)보통보통
러닝 커브중간 (클래스 암기 필요)낮음낮음
SSR 성능우수우수추가 설정 필요
적합한 용도디자인 시스템, 빠른 개발컴포넌트 스타일 캡슐화동적 스타일링

Tailwind CSS를 팀에서 효과적으로 사용하는 방법

Tailwind CSS의 가장 큰 장점 중 하나는 디자인 토큰이 중앙에서 관리된다는 것입니다. tailwind.config.jstheme 설정에서 색상, 간격, 폰트 등을 정의하면, 이 값들이 전체 프로젝트에서 일관되게 사용됩니다. 디자이너가 Figma에서 정의한 컬러 팔레트를 그대로 Tailwind 설정에 반영해두면, 개발자가 임의로 색상 값을 입력하는 일이 없어집니다. 이 방식으로 디자인 일관성을 코드 레벨에서 강제할 수 있습니다. 팀 내에서 클래스 순서에 대한 합의도 필요합니다. Prettier 플러그인인 prettier-plugin-tailwindcss를 사용하면 Tailwind 권장 순서로 클래스를 자동 정렬해줘서 코드 리뷰 시 클래스 순서 관련 의견 충돌이 줄어듭니다.

Tailwind CSS의 단점으로 자주 거론되는 것은 긴 클래스 문자열이 HTML을 읽기 어렵게 만든다는 것입니다. 이를 해결하는 실무적인 방법은 반복되는 클래스 조합을 컴포넌트로 추상화하는 것입니다. React나 Vue 같은 컴포넌트 기반 프레임워크를 사용한다면, 공통 UI 요소를 컴포넌트로 만들어 내부에서 Tailwind 클래스를 관리하면 사용하는 쪽의 코드는 깔끔하게 유지됩니다. @apply 지시어는 반복되는 유틸리티 조합을 CSS 클래스로 묶을 때 사용할 수 있지만, 지나치게 사용하면 Tailwind의 장점인 명시성이 사라지므로 꼭 필요한 경우에만 제한적으로 씁니다. Tailwind를 도입했다면 기존의 전통적인 CSS 방식과 섞지 않는 것이 일관성 유지에 중요합니다.