Tailwind CSS

Tailwind CSS

보통 웹사이트를 꾸밀 때는 별도의 CSS 파일에 코드를 길게 작성해야 한다. 하지만 Tailwind는 "이미 만들어진 태그(Class)"를 HTML에 바로 붙여서 디자인하는 방식이다.


테일윈드 공식

테일윈드 치트시트

공식테일윈드 피그마 스타일파일

테일윈드 디자인토큰 생성기 피그마 플러그인


1. Basics — 설치

NPM 설치 (Vite 기준)

  1. 터미널에 아래 명령어 입력
npm install tailwindcss @tailwindcss/vite
  1. vite.config.js 파일에 아래 코드 추가
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'   // ← 추가

export default defineConfig({
  plugins: [react(), tailwindcss()],
})
  1. src/index.css 에 아래 코드 추가
@import "tailwindcss";

CDN 설치

HTML의 <head> 태그 안에 아래 코드를 삽입한다.

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://unpkg.com/@tailwindcss/browser@4"></script>
</head>
<body>
  <h1 class="text-3xl font-bold text-blue-600 underline">
    Hello, Tailwind!
  </h1>
</body>
</html>

Tip: 유틸리티 우선(Utility-First)

  • 기존 방식: .btn { background: blue; } 클래스를 정의하고 HTML에서 적용한다.
  • Tailwind 방식: class="bg-blue-500 text-white"와 같이 이미 정의된 클래스를 조합한다.

2. Sizing

2.1. Width

클래스
w-{n} spacing 스케일 (w-4 = 16px)
w-full 100%
w-screen 100vw
w-auto auto
w-1/2, w-1/3, w-2/3 50%, 33.3%, 66.6%
w-1/4, w-3/4 25%, 75%
w-[200px] 임의값
min-w-0, min-w-full 최솟값
max-w-sm ~ max-w-7xl 최댓값 (sm=24rem~)

2.2. Height

클래스
h-{n} spacing 스케일
h-full 100%
h-screen 100vh
h-auto auto
min-h-screen min-height: 100vh
min-h-0 min-height: 0
h-dvh 100dvh (동적 뷰포트)
h-svh 100svh (소형 뷰포트)

2.3. size 단축 클래스

클래스
size-10 w-10 h-10
size-[200px] w-200px h-200px
// 1단계: w-full, h-16 — 고정 크기
<div className="w-full">가로 100%</div>
<div className="h-16">높이 64px</div>
// 2단계: 비율 — 부모 기준 백분율
<div className="w-1/2">부모의 50%</div>
<div className="w-1/3">부모의 33%</div>
<div className="w-2/3">부모의 66%</div>
// 3단계: max-w — 최대 너비 제한 (반응형에 자주 사용)
<div className="w-full max-w-xl">최대 576px까지만</div>
<div className="w-full max-w-4xl mx-auto">최대 너비 + 가운데 정렬</div>
// 4단계: size — 가로·세로 동시 지정
<div className="size-10">40x40</div>
<div className="size-16">64x64</div>
<div className="size-[200px]">200x200</div>

3. Typography — 타이포그래피

3.1. Font Size (text-*)

클래스 크기 line-height
text-xs 12px 1rem
text-sm 14px 1.25rem
text-base 16px 1.5rem
text-lg 18px 1.75rem
text-xl 20px 1.75rem
text-2xl 24px 2rem
text-3xl 30px 2.25rem
text-4xl 36px 2.5rem
text-5xl 48px 1
text-6xl 60px 1

3.2. Font Weight

font-thin       /* 100 */
font-extralight /* 200 */
font-light      /* 300 */
font-normal     /* 400 */
font-medium     /* 500 */
font-semibold   /* 600 */
font-bold       /* 700 */
font-extrabold  /* 800 */
font-black      /* 900 */

3.3. Text 색상

text-white        text-black
text-gray-500     text-gray-900
text-yellow-300   text-yellow-400
text-blue-600     text-red-500
text-white/80     /* 투명도 포함 */

3.4. Text 정렬 · 변환 · 장식

/* 정렬 */
text-left   text-center   text-right   text-justify

/* 변환 */
uppercase   lowercase   capitalize   normal-case

/* 장식 */
underline   line-through   no-underline   overline

/* 오버플로 처리 */
truncate          /* 한 줄 말줄임 */
line-clamp-2      /* 2줄 말줄임 */
line-clamp-3      /* 3줄 말줄임 */
whitespace-nowrap /* 줄바꿈 금지 */

3.5. Letter Spacing · Line Height

/* 자간 */
tracking-tight    tracking-normal    tracking-wide    tracking-widest

/* 행간 */
leading-none      /* 1 */
leading-tight     /* 1.25 */
leading-normal    /* 1.5 */
leading-loose     /* 2 */
leading-[1.8]     /* 임의값 */
// 1단계: text-size — 글자 크기
<p className="text-sm">작은 텍스트 (14px)</p>
<p className="text-base">기본 텍스트 (16px)</p>
<p className="text-xl">큰 텍스트 (20px)</p>
<p className="text-4xl">제목용 텍스트 (36px)</p>
// 2단계: font-weight — 굵기
<p className="font-normal">일반 굵기</p>
<p className="font-bold">굵게</p>
<p className="font-black">가장 굵게</p>
// 3단계: text-color — 색상
<p className="text-white">흰색</p>
<p className="text-gray-400">회색</p>
<p className="text-yellow-400">노란색</p>
// 4단계: text-align — 정렬
<p className="text-left">왼쪽 정렬</p>
<p className="text-center">가운데 정렬</p>
<p className="text-right">오른쪽 정렬</p>
// 5단계: truncate / line-clamp — 넘치는 텍스트 처리
<p className="truncate">한 줄을 넘으면 말줄임표로 잘림...</p>
<p className="line-clamp-2">두 줄을 넘으면 잘림. 긴 텍스트 긴 텍스트 긴 텍스트 긴 텍스트...</p>


4. Backgrounds — 배경

4.1. 기본 색상 팔레트

Tailwind의 색상은 색상명-숫자 형태이다. 숫자가 클수록 어두워진다 (50 가장 밝음, 950 가장 어두움).

색상명 대표 클래스 예시
slate, gray, zinc, neutral, stone 무채색 계열
red, orange, amber, yellow 따뜻한 계열
lime, green, emerald, teal 초록 계열
cyan, sky, blue, indigo 파란 계열
violet, purple, fuchsia, pink, rose 보라·분홍 계열

4.2. 배경색 적용

/* 배경색 */
bg-white          bg-black
bg-gray-900       bg-gray-800
bg-yellow-400     bg-blue-600

/* 투명도 (슬래시 문법) */
bg-black/50       /* background: rgba(0,0,0,0.5) */
bg-white/10       /* background: rgba(255,255,255,0.1) */
bg-black/90       /* GOFLIX 헤더에 사용 */

4.3. 테두리 색상

border-gray-200   border-yellow-400   border-transparent
// 1단계: bg-color — 단색 배경
<div className="bg-black">검은 배경</div>
<div className="bg-gray-800">어두운 회색 배경</div>
<div className="bg-yellow-400">노란 배경</div>
// 2단계: bg-color + text-color — 배경과 텍스트 색상 함께
<div className="bg-gray-900 text-white">어두운 배경에 흰 텍스트</div>
<div className="bg-yellow-400 text-black">노란 배경에 검은 텍스트</div>
// 3단계: bg-color/투명도 — 슬래시로 불투명도 조절
<div className="bg-black/50">50% 투명한 검은 배경</div>
<div className="bg-black/90">90% 불투명한 검은 배경</div>
// 4단계: bg-gradient — 그라디언트 배경
<div className="bg-gradient-to-r from-black to-gray-800">좌 → 우</div>
<div className="bg-gradient-to-t from-black to-transparent">아래 → 위(투명)</div>

5. Borders — 테두리 & Ring

5.1. Border Width · Color · Style


<div class="border border-gray-200">1px 테두리</div>
<div class="border-2 border-blue-500">2px 파란 테두리</div>
<div class="border-4 border-dashed border-red-400">4px 점선</div>


<div class="border-b border-gray-200">하단만</div>
<div class="border-t-2 border-l-2 border-blue-300">상단+좌측</div>


<div class="rounded-sm">약간</div>
<div class="rounded-lg">중간</div>
<div class="rounded-2xl">큰 (카드)</div>
<div class="rounded-full">원형</div>

None: 1: border — 기본 1px 회색 테두리
2: border-2 — 2px, border-blue-500 — 파란색
3: border-dashed — 점선 스타일
5: border-b — 아래쪽만, border-t-2 border-l-2 — 위쪽과 왼쪽 2px
9~12: rounded-* — 모서리 반지름 (sm < lg < 2xl, full=50%)


18. GOFLIX 프로젝트 적용 예시

Tailwind로 영화 정보 사이트를 만드는 실전 예시입니다.

18.1. Header 분석

<header className="fixed top-0 left-0 w-full py-4 px-2 bg-black/90 z-50">
  {/* fixed: 스크롤해도 고정 */}
  {/* top-0 left-0: 화면 최상단 좌측 */}
  {/* w-full: 전체 너비 */}
  {/* py-4 px-2: 상하 16px, 좌우 8px 패딩 */}
  {/* bg-black/90: 검은색 배경 90% 불투명 */}
  {/* z-50: 다른 요소 위에 표시 */}
  <div className="container mx-auto">
    <Link to="/">
      <h1 className="text-3xl text-yellow-300 font-bold">
        {/* text-3xl: 30px 텍스트 */}
        {/* text-yellow-300: 연한 노란색 */}
        {/* font-bold: 굵은 글씨 */}
        GOFLIX
      </h1>
    </Link>
  </div>
</header>

18.2. 영화 카드 컴포넌트 패턴

function MovieCard({ movie }) {
  return (
    <div className="group relative rounded-lg overflow-hidden cursor-pointer
                    transition-transform duration-300 hover:scale-105
                    shadow-lg hover:shadow-yellow-400/30">
      {/* 포스터 이미지 */}
      <img
        src={`https://image.tmdb.org/t/p/w500${movie.poster_path}`}
        alt={movie.title}
        className="w-full aspect-[2/3] object-cover"
      />
      {/* 호버 오버레이 */}
      <div className="absolute inset-0 bg-black/70 opacity-0 group-hover:opacity-100
                      transition-opacity duration-300 flex flex-col justify-end p-4">
        <h3 className="text-white font-bold text-sm line-clamp-2">{movie.title}</h3>
        <p className="text-yellow-300 text-xs mt-1">⭐ {movie.vote_average.toFixed(1)}</p>
      </div>
    </div>
  );
}

18.3. 전체 페이지 레이아웃

// App.jsx
<main className="bg-black text-white min-h-screen pt-16">
  {/* bg-black: 검은 배경 */}
  {/* text-white: 기본 텍스트 흰색 */}
  {/* min-h-screen: 최소 전체 높이 */}
  {/* pt-16: 상단 64px (fixed 헤더 높이만큼) */}
  <Outlet />
</main>

// 홈 페이지
<section className="container mx-auto px-4 py-8">
  <h2 className="text-2xl font-bold mb-6 text-yellow-300">인기 영화</h2>
  <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4">
    {movies.map(movie => <MovieCard key={movie.id} movie={movie} />)}
  </div>
</section>

18.4. 버튼 스타일 패턴

{/* 주요 액션 버튼 */}
<button className="bg-yellow-400 text-black font-bold px-6 py-2 rounded-lg
                   hover:bg-yellow-300 active:scale-95
                   transition-all duration-200 cursor-pointer">
  자세히 보기
</button>

{/* 보조 버튼 (아웃라인) */}
<button className="border-2 border-white text-white font-semibold px-6 py-2 rounded-lg
                   hover:bg-white hover:text-black
                   transition-all duration-200 cursor-pointer">
  목록 추가
</button>

18.5. 영화 상세 페이지

function MovieDetail({ movie }) {
  return (
    <div className="relative min-h-screen bg-black text-white">
      {/* 배경 이미지 */}
      <div className="relative h-[60vh]">
        <img
          src={`https://image.tmdb.org/t/p/original${movie.backdrop_path}`}
          className="w-full h-full object-cover"
        />
        <div className="absolute inset-0 bg-gradient-to-t from-black via-black/40 to-transparent" />
      </div>

      {/* 콘텐츠 */}
      <div className="container mx-auto px-4 -mt-32 relative z-10">
        <div className="flex flex-col md:flex-row gap-8">
          <img
            src={`https://image.tmdb.org/t/p/w300${movie.poster_path}`}
            className="w-40 md:w-56 rounded-xl shadow-2xl flex-none mx-auto md:mx-0"
          />
          <div className="flex-1">
            <h1 className="text-3xl md:text-5xl font-black">{movie.title}</h1>
            <div className="flex items-center gap-3 mt-3 text-sm text-gray-400">
              <span className="text-yellow-400 font-bold">⭐ {movie.vote_average.toFixed(1)}</span>
              <span>{movie.release_date.slice(0, 4)}</span>
            </div>
            <p className="mt-4 text-gray-300 leading-relaxed max-w-2xl line-clamp-4 md:line-clamp-none">
              {movie.overview}
            </p>
            <div className="flex gap-3 mt-6">
              <button className="bg-yellow-400 text-black font-bold px-6 py-3 rounded-lg
                                 hover:bg-yellow-300 active:scale-95 transition-all duration-200">
                ▶ 재생
              </button>
              <button className="border border-white/40 text-white px-6 py-3 rounded-lg
                                 hover:bg-white/10 transition-all duration-200">
                + 내 목록
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  )
}

Tip: 클래스 조합 팁

복잡한 컴포넌트는 관심사별로 줄을 나눠 읽기 좋게 작성한다.

레이아웃 → 크기 → 색상 → 상태 순으로 배치하면 유지보수가 편하다.

Warning: 자주 하는 실수

  • hover:scale-105만 쓰면 애니메이션이 없음 → transition-transform duration-300 필수
  • opacity-0 group-hover:opacity-100을 쓸 때 부모에 group 클래스 빠뜨리지 않기
  • fixed 헤더가 있으면 main에 pt-{헤더높이} 필수 (겹침 방지)

6. Layout — 레이아웃 (Display · Position)

6.1. Display

클래스 CSS 설명
block display: block 블록 요소
inline display: inline 인라인 요소
inline-block display: inline-block 인라인 블록
flex display: flex 플렉스 컨테이너
inline-flex display: inline-flex 인라인 플렉스
grid display: grid 그리드 컨테이너
hidden display: none 숨김
<div className="block">block — 한 줄 전체를 차지</div>
<span className="inline">inline — 내용 크기만큼, 줄바꿈 없음</span>
<span className="inline-block">inline-block — 줄바꿈 없이 나란히</span>
<div className="hidden">hidden — 화면에서 완전히 사라짐</div>

6.2. Position

클래스 CSS
static position: static
relative position: relative
absolute position: absolute
fixed position: fixed
sticky position: sticky

6.3. 위치 지정 (inset)

클래스 의미
top-0 위에서 0
left-0 왼쪽에서 0
inset-0 상하좌우 모두 0
inset-x-0 좌우만 0
inset-y-0 상하만 0
// 1단계: relative — 자식의 기준점 역할
<div className="relative">
  기준이 되는 부모
</div>
// 2단계: absolute + top/left — 부모 기준으로 위치 지정
<div className="relative">
  <div className="absolute top-0 left-0">왼쪽 위에 배치</div>
  <div className="absolute top-0 right-0">오른쪽 위에 배치</div>
</div>
// 3단계: inset-0 — 부모 전체를 꽉 채움
<div className="relative">
  <div className="absolute inset-0">부모 전체 크기로 채움</div>
</div>
// 4단계: fixed — 스크롤해도 화면에 고정
<header className="fixed top-0 left-0">스크롤해도 고정되는 헤더</header>
// 5단계: sticky — 스크롤 시 특정 위치에 달라붙음
<h2 className="sticky top-0">스크롤하면 상단에 고정되는 제목</h2>

6.4. z-index

// 숫자가 클수록 위에 표시됨
<div className="z-0">맨 아래</div>
<div className="z-10">그 위</div>
<div className="z-50">가장 위</div>


7. Flexbox

가장 많이 쓰는 레이아웃 방식. 방향, 줄바꿈, 자식 크기를 클래스 조합으로 제어한다.

7.1. 방향 (flex-direction)

클래스 CSS
flex-row flex-direction: row (기본값)
flex-row-reverse flex-direction: row-reverse
flex-col flex-direction: column
flex-col-reverse flex-direction: column-reverse

7.2. 줄바꿈 · 자식 크기

/* 줄바꿈 */
flex-wrap      flex-nowrap      flex-wrap-reverse

/* 자식 요소 크기 제어 */
flex-1         /* flex: 1 1 0% — 공간을 균등 분할 */
flex-auto      /* flex: 1 1 auto */
flex-none      /* flex: none — 크기 고정 */

/* 개별 크기 */
grow           /* flex-grow: 1 */
grow-0         /* flex-grow: 0 */
shrink         /* flex-shrink: 1 */
shrink-0       /* flex-shrink: 0 */
// 1단계: flex — 자식을 가로로 나열
<div className="flex">
  <div>아이템 1</div>
  <div>아이템 2</div>
  <div>아이템 3</div>
</div>
// 2단계: flex-col — 세로로 나열
<div className="flex flex-col">
  <div>위</div>
  <div>중간</div>
  <div>아래</div>
</div>
// 3단계: gap — 자식 사이 간격
<div className="flex gap-4">
  <div>아이템 1</div>
  <div>아이템 2</div>
  <div>아이템 3</div>
</div>
// 4단계: flex-1 / flex-none — 자식 크기 제어
<div className="flex">
  <div className="flex-none">고정 크기</div>
  <div className="flex-1">남은 공간을 모두 차지</div>
</div>
// 5단계: flex-wrap — 넘치면 줄바꿈
<div className="flex flex-wrap gap-2">
  <div>태그 1</div>
  <div>태그 2</div>
  <div>태그 3</div>
  <div>태그 4</div>
  <div>태그 5</div>
</div>

7.3. Container

container는 화면 크기에 따라 max-width를 자동으로 맞춰주는 클래스다. 단독으로는 왼쪽 정렬이므로, mx-auto를 함께 써서 가운데 정렬한다.

브레이크포인트 적용되는 max-width
기본 (모바일) 100%
sm (640px~) 640px
md (768px~) 768px
lg (1024px~) 1024px
xl (1280px~) 1280px
2xl (1536px~) 1536px
// 1단계: container 기본 — 반응형 max-width 자동 적용
<div className="container">콘텐츠</div>
// 2단계: mx-auto 추가 — 가운데 정렬
<div className="container mx-auto">콘텐츠</div>
// 3단계: 실전 — 페이지 전체 레이아웃에 적용
<main>
  <section className="container mx-auto">
    <h2>인기 영화</h2>
    ...
  </section>

  <section className="container mx-auto">
    <h2>최신 영화</h2>
    ...
  </section>
</main>


8. Grid

2차원 레이아웃. 영화 카드 목록처럼 열을 고정하거나 반응형으로 배치할 때 사용한다.

8.1. 열(Column) 정의

클래스 CSS
grid-cols-1 grid-template-columns: repeat(1, 1fr)
grid-cols-2 ~ 12 2~12 등분
grid-cols-none 컬럼 정의 없음
grid-cols-[200px_1fr] 임의값 지정

8.2. 간격

gap-4          /* row-gap + column-gap: 1rem */
gap-x-6        /* column-gap: 1.5rem */
gap-y-4        /* row-gap: 1rem */

8.3. 자식 요소 병합 (span)

col-span-2     /* 열 2칸 차지 */
col-span-full  /* 전체 열 차지 */
row-span-2     /* 행 2칸 차지 */
// 1단계: grid + grid-cols — 열 개수 지정
<div className="grid grid-cols-3">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
</div>
// 2단계: gap — 셀 사이 간격 추가
<div className="grid grid-cols-3 gap-4">
  <div>1</div>
  <div>2</div>
  <div>3</div>
</div>
// 3단계: col-span — 특정 셀이 여러 칸을 차지
<div className="grid grid-cols-3 gap-4">
  <div className="col-span-2">넓은 셀 (2칸)</div>
  <div>1칸</div>
  <div>1칸</div>
  <div className="col-span-full">전체 너비 셀</div>
</div>
// 4단계: 반응형 — 화면 크기에 따라 열 수 변경
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
  {movies.map(movie => (
    <MovieCard key={movie.id} movie={movie} />
  ))}
</div>


9. Alignment — 정렬 (Justify · Align)

Flexbox와 Grid에서 아이템을 정렬하는 유틸리티이다.

9.1. 주축 정렬 (justify-content)

클래스 CSS
justify-start justify-content: flex-start
justify-center justify-content: center
justify-end justify-content: flex-end
justify-between justify-content: space-between
justify-around justify-content: space-around
justify-evenly justify-content: space-evenly

9.2. 교차축 정렬 (align-items)

클래스 CSS
items-start align-items: flex-start
items-center align-items: center
items-end align-items: flex-end
items-stretch align-items: stretch
items-baseline align-items: baseline

9.3. Grid 정렬

place-items-center    /* align-items + justify-items: center */
place-content-center
// 1단계: justify-center — 가로 중앙 정렬
<div className="flex justify-center">
  <div>가운데 배치됨</div>
</div>
// 2단계: justify-between — 양 끝으로 배치
<div className="flex justify-between">
  <div>왼쪽</div>
  <div>오른쪽</div>
</div>
// 3단계: items-center — 세로 중앙 정렬
<div className="flex items-center">
  <div>세로 중앙에 배치됨</div>
</div>
// 4단계: justify + items 조합 — 완전 중앙
<div className="flex justify-center items-center">
  <div>정중앙에 배치됨</div>
</div>
// 5단계: place-items-center — grid에서 셀 안 정중앙
<div className="grid grid-cols-3 place-items-center">
  <div>★</div>
  <div>★</div>
  <div>★</div>
</div>


10. Spacing — 간격 (Margin · Padding · Gap)

기본 단위: 1 = 4px (0.25rem). 4 = 16px, 8 = 32px처럼 4배수로 계산한다.

10.1. Margin

클래스 방향 예시
m-{n} 전체 m-4 → 16px 사방
mx-{n} 좌우 mx-auto → 가운데 정렬
my-{n} 상하 my-8
mt-{n} mt-16
mr-{n} 오른쪽
mb-{n} 아래
ml-{n} 왼쪽
-m-{n} 음수 마진 -mt-4

10.2. Padding (같은 패턴)

p-4   px-6   py-3   pt-2   pr-4   pb-6   pl-2

10.3. 자주 쓰는 값 참고표

클래스 숫자 rem px
1 0.25rem 4px
2 0.5rem 8px
3 0.75rem 12px
4 1rem 16px
5 1.25rem 20px
6 1.5rem 24px
8 2rem 32px
10 2.5rem 40px
12 3rem 48px
16 4rem 64px
20 5rem 80px
24 6rem 96px
// 1단계: p — 사방 패딩
<div className="p-4">사방 16px 여백</div>
<div className="p-8">사방 32px 여백</div>
// 2단계: px / py — 방향별 패딩
<div className="px-6">좌우만 24px</div>
<div className="py-3">상하만 12px</div>
<div className="px-6 py-3">좌우 24px + 상하 12px</div>
// 3단계: mt / mb — 위아래 마진
<div className="mt-8">위에 32px 여백</div>
<div className="mb-4">아래에 16px 여백</div>
// 4단계: mx-auto — 가운데 정렬
<div className="mx-auto">가운데 정렬</div>
// 5단계: space-y — 자식 요소 사이 세로 간격
<div className="space-y-4">
  <div>첫 번째 항목</div>
  <div>두 번째 항목</div>
  <div>세 번째 항목</div>
</div>


11. Effects — 그림자 & 불투명도

11.1. Box Shadow

shadow-sm      /* 작은 그림자 */
shadow         /* 기본 그림자 */
shadow-md      /* 중간 그림자 */
shadow-lg      /* 큰 그림자 */
shadow-xl      /* 더 큰 그림자 */
shadow-2xl     /* 가장 큰 그림자 */
shadow-none    /* 그림자 제거 */

/* 색상 그림자 */
shadow-lg shadow-black/50

11.2. Opacity (불투명도)

opacity-0         /* 완전 투명 */
opacity-50        /* 반투명 */
opacity-100       /* 불투명 */
// 1단계: shadow — 그림자 크기
<div className="shadow">기본 그림자</div>
<div className="shadow-md">중간 그림자</div>
<div className="shadow-xl">큰 그림자</div>
// 2단계: shadow-color — 색상 그림자
<div className="shadow-lg shadow-black/50">검은 그림자</div>
<div className="shadow-lg shadow-yellow-400/30">노란 그림자</div>
// 3단계: opacity — 요소 전체 투명도
<div className="opacity-100">완전 불투명</div>
<div className="opacity-50">반투명</div>
<div className="opacity-0">완전 투명 (공간은 차지)</div>


12. Filters — 필터 (Blur · Backdrop)

blur-none    blur-sm    blur    blur-md    blur-lg    blur-xl

/* 배경 블러 (유리 효과) */
backdrop-blur-sm    backdrop-blur-md    backdrop-blur-lg
// 1단계: blur — 요소 자체를 흐리게
<img className="blur-none" src={img} alt="" />
<img className="blur-sm" src={img} alt="" />
<img className="blur-lg" src={img} alt="" />
// 2단계: backdrop-blur — 요소 뒤 배경을 흐리게
<div className="backdrop-blur-sm">약하게 흐린 배경</div>
<div className="backdrop-blur-md">중간 흐린 배경</div>
<div className="backdrop-blur-lg">많이 흐린 배경</div>
// 3단계: backdrop-blur + bg-*/투명도 — 유리 효과
<div className="backdrop-blur-md bg-white/10">유리처럼 반투명한 카드</div>


13. Transitions & Animation — 트랜지션

transition          /* all 속성 */
transition-colors   /* 색상만 */
transition-transform
transition-opacity
duration-150        /* 150ms */
duration-300        /* 300ms */
ease-in    ease-out    ease-in-out
// 1단계: transition — 변화를 부드럽게 (hover와 함께)
<div className="transition hover:opacity-50">호버 시 서서히 반투명</div>
// 2단계: duration — 애니메이션 시간
<div className="transition duration-150 hover:opacity-50">빠름 (150ms)</div>
<div className="transition duration-500 hover:opacity-50">느림 (500ms)</div>
// 3단계: transition-colors — 색상만 전환
<div className="transition-colors duration-200 hover:bg-yellow-400">
  호버 시 배경색만 전환
</div>
// 4단계: transition-transform — 크기·위치 전환
<div className="transition-transform duration-300 hover:scale-105">
  호버 시 크기만 전환
</div>
// 5단계: ease — 가속도 곡선
<div className="transition duration-300 ease-in hover:opacity-0">천천히 시작</div>
<div className="transition duration-300 ease-out hover:opacity-0">천천히 끝</div>
<div className="transition duration-300 ease-in-out hover:opacity-0">양쪽 천천히</div>


14. Transforms — 변형

scale-95    scale-100    scale-105    scale-110
-translate-y-1    translate-x-2
rotate-45    rotate-90    rotate-180
// 1단계: scale — 크기 변형
<div className="scale-75">75% 축소</div>
<div className="scale-100">기본 크기</div>
<div className="scale-110">110% 확대</div>
// 2단계: translate — 위치 이동 (공간은 유지)
<div className="translate-x-4">오른쪽으로 16px</div>
<div className="-translate-y-2">위로 8px</div>
// 3단계: rotate — 회전
<div className="rotate-45">45도 회전</div>
<div className="rotate-90">90도 회전</div>
<div className="rotate-180">180도 회전</div>
// 4단계: transition + transform — 부드러운 변형
<div className="transition-transform duration-300 hover:scale-110">
  호버 시 서서히 확대
</div>
<div className="transition-transform duration-300 hover:-translate-y-1">
  호버 시 서서히 위로 이동
</div>


15. Interactivity — 상호작용 (State Variants · Cursor)

15.1. Cursor

cursor-pointer    cursor-default    cursor-not-allowed    cursor-wait

15.2. 주요 State Variants

클래스 앞에 상태:를 붙이면 해당 상태일 때만 적용된다.

Variant 설명 예시
hover: 마우스 올림 hover:bg-yellow-400
focus: 포커스 focus:ring-2
active: 클릭 중 active:scale-95
disabled: 비활성화 disabled:opacity-50
checked: 체크됨 checked:bg-blue-600
group-hover: 부모 hover 시 group-hover:opacity-100
peer-focus: 형제 포커스 시 peer-focus:text-blue-500
first: 첫 번째 자식 first:mt-0
last: 마지막 자식 last:mb-0
odd: / even: 홀수/짝수 odd:bg-gray-50
// 1단계: hover: — 마우스를 올렸을 때
<div className="hover:opacity-50">호버 시 반투명</div>
<div className="hover:bg-yellow-400">호버 시 노란 배경</div>
// 2단계: focus: — 포커스 받았을 때 (입력 필드 등)
<input className="focus:outline-none" />
<input className="focus:ring-2 focus:ring-yellow-400" />
// 3단계: active: — 클릭하는 순간
<button className="active:scale-95">클릭 시 줄어듦</button>
<button className="active:opacity-70">클릭 시 반투명</button>
// 4단계: disabled: — 비활성화 상태
<button disabled className="disabled:opacity-50">비활성 (흐리게)</button>
<button disabled className="disabled:cursor-not-allowed">비활성 (커서 금지)</button>
// 5단계: group-hover: — 부모에 hover 시 자식에 적용
<div className="group">
  <p className="group-hover:text-yellow-400">부모에 호버하면 색상 변경</p>
</div>

// 부모 hover 시 숨겨진 오버레이 표시
<div className="group relative">
  <img src={poster} />
  <div className="absolute inset-0 opacity-0 group-hover:opacity-100">
    오버레이
  </div>
</div>
// 6단계: odd: / even: — 홀짝 번째 스타일
<ul>
  <li className="odd:bg-gray-900 even:bg-gray-800">항목 1 (홀수 → 어두운)</li>
  <li className="odd:bg-gray-900 even:bg-gray-800">항목 2 (짝수 → 밝은)</li>
  <li className="odd:bg-gray-900 even:bg-gray-800">항목 3 (홀수 → 어두운)</li>
</ul>


16. 반응형 (Breakpoint)

Tailwind는 모바일 퍼스트이다. 기본값이 모바일이고, 접두사로 더 큰 화면을 지정한다.

16.1. 기본 브레이크포인트

접두사 최소 너비 기기
(없음) 0px~ 모바일 (기본)
sm: 640px~ 소형 태블릿
md: 768px~ 태블릿
lg: 1024px~ 노트북
xl: 1280px~ 데스크탑
2xl: 1536px~ 대형 모니터
// 1단계: 브레이크포인트 하나 — md 이상에서 적용
<p className="text-sm md:text-xl">md 이상에서 커짐</p>
// 2단계: 브레이크포인트 두 개 — 단계적으로 변경
<p className="text-sm md:text-lg lg:text-2xl">화면이 커질수록 텍스트도 커짐</p>
// 3단계: hidden / block 조합 — 특정 화면에서 보이기/숨기기
<div className="hidden md:block">md 이상에서만 보임</div>
<div className="block md:hidden">md 미만에서만 보임 (모바일 전용)</div>
// 4단계: flex-col → flex-row — 모바일: 세로, 데스크탑: 가로
<div className="flex flex-col md:flex-row">
  <div>첫 번째</div>
  <div>두 번째</div>
</div>
// 5단계: grid-cols 반응형 — 화면 크기에 따라 열 수 변경
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
  <div>카드 1</div>
  <div>카드 2</div>
  <div>카드 3</div>
  <div>카드 4</div>
</div>

17. Dark Mode

17.1. 설정 (media 모드 — OS 자동)

// OS 다크모드 설정에 따라 자동 전환
<div className="bg-white dark:bg-gray-900">
  라이트: 흰 배경 / 다크: 어두운 배경
</div>

17.2. 수동 토글 방식 (class 모드)

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

@custom-variant dark (&:where(.dark, .dark *));
// HTML 루트에 dark 클래스 추가/제거로 제어
document.documentElement.classList.toggle('dark')
// 1단계: dark: 텍스트 색상
<p className="text-black dark:text-white">라이트: 검은색 / 다크: 흰색</p>
<p className="text-gray-700 dark:text-gray-300">라이트: 진한 회색 / 다크: 밝은 회색</p>
// 2단계: dark: 배경 색상
<div className="bg-white dark:bg-gray-900">라이트: 흰 배경 / 다크: 어두운 배경</div>
<div className="bg-gray-100 dark:bg-gray-800">라이트: 밝은 회색 / 다크: 짙은 회색</div>
// 3단계: 텍스트 + 배경 조합
<div className="bg-white dark:bg-gray-900 text-black dark:text-white">
  다크모드 대응 카드
</div>
// 4단계: 토글 버튼으로 직접 제어
function DarkToggle() {
  const [dark, setDark] = useState(false)

  const toggle = () => {
    setDark(prev => !prev)
    document.documentElement.classList.toggle('dark')
  }

  return (
    <button onClick={toggle}>
      {dark ? '🌙 다크' : '☀️ 라이트'}
    </button>
  )
}

18.1. Header 분석

<header className="fixed top-0 left-0 w-full py-4 px-2 bg-black/90 z-50">
  {/* fixed: 스크롤해도 고정 */}
  {/* top-0 left-0: 화면 최상단 좌측 */}
  {/* w-full: 전체 너비 */}
  {/* py-4 px-2: 상하 16px, 좌우 8px 패딩 */}
  {/* bg-black/90: 검은색 배경 90% 불투명 */}
  {/* z-50: 다른 요소 위에 표시 */}
  <div className="container mx-auto">
    <Link to="/">
      <h1 className="text-3xl text-yellow-300 font-bold">
        {/* text-3xl: 30px 텍스트 */}
        {/* text-yellow-300: 연한 노란색 */}
        {/* font-bold: 굵은 글씨 */}
        GOFLIX
      </h1>
    </Link>
  </div>
</header>

18.2. 영화 카드 컴포넌트 패턴

function MovieCard({ movie }) {
  return (
    <div className="group relative rounded-lg overflow-hidden cursor-pointer
                    transition-transform duration-300 hover:scale-105
                    shadow-lg hover:shadow-yellow-400/30">
      {/* 포스터 이미지 */}
      <img
        src={`https://image.tmdb.org/t/p/w500${movie.poster_path}`}
        alt={movie.title}
        className="w-full aspect-[2/3] object-cover"
      />
      {/* 호버 오버레이 */}
      <div className="absolute inset-0 bg-black/70 opacity-0 group-hover:opacity-100
                      transition-opacity duration-300 flex flex-col justify-end p-4">
        <h3 className="text-white font-bold text-sm line-clamp-2">{movie.title}</h3>
        <p className="text-yellow-300 text-xs mt-1">⭐ {movie.vote_average.toFixed(1)}</p>
      </div>
    </div>
  );
}

18.3. 전체 페이지 레이아웃

// App.jsx
<main className="bg-black text-white min-h-screen pt-16">
  {/* bg-black: 검은 배경 */}
  {/* text-white: 기본 텍스트 흰색 */}
  {/* min-h-screen: 최소 전체 높이 */}
  {/* pt-16: 상단 64px (fixed 헤더 높이만큼) */}
  <Outlet />
</main>

// 홈 페이지
<section className="container mx-auto px-4 py-8">
  <h2 className="text-2xl font-bold mb-6 text-yellow-300">인기 영화</h2>
  <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4">
    {movies.map(movie => <MovieCard key={movie.id} movie={movie} />)}
  </div>
</section>

18.4. 버튼 스타일 패턴

{/* 주요 액션 버튼 */}
<button className="bg-yellow-400 text-black font-bold px-6 py-2 rounded-lg
                   hover:bg-yellow-300 active:scale-95
                   transition-all duration-200 cursor-pointer">
  자세히 보기
</button>

{/* 보조 버튼 (아웃라인) */}
<button className="border-2 border-white text-white font-semibold px-6 py-2 rounded-lg
                   hover:bg-white hover:text-black
                   transition-all duration-200 cursor-pointer">
  목록 추가
</button>

18.5. 영화 상세 페이지

function MovieDetail({ movie }) {
  return (
    <div className="relative min-h-screen bg-black text-white">
      {/* 배경 이미지 */}
      <div className="relative h-[60vh]">
        <img
          src={`https://image.tmdb.org/t/p/original${movie.backdrop_path}`}
          className="w-full h-full object-cover"
        />
        <div className="absolute inset-0 bg-gradient-to-t from-black via-black/40 to-transparent" />
      </div>

      {/* 콘텐츠 */}
      <div className="container mx-auto px-4 -mt-32 relative z-10">
        <div className="flex flex-col md:flex-row gap-8">
          <img
            src={`https://image.tmdb.org/t/p/w300${movie.poster_path}`}
            className="w-40 md:w-56 rounded-xl shadow-2xl flex-none mx-auto md:mx-0"
          />
          <div className="flex-1">
            <h1 className="text-3xl md:text-5xl font-black">{movie.title}</h1>
            <div className="flex items-center gap-3 mt-3 text-sm text-gray-400">
              <span className="text-yellow-400 font-bold">⭐ {movie.vote_average.toFixed(1)}</span>
              <span>{movie.release_date.slice(0, 4)}</span>
            </div>
            <p className="mt-4 text-gray-300 leading-relaxed max-w-2xl line-clamp-4 md:line-clamp-none">
              {movie.overview}
            </p>
            <div className="flex gap-3 mt-6">
              <button className="bg-yellow-400 text-black font-bold px-6 py-3 rounded-lg
                                 hover:bg-yellow-300 active:scale-95 transition-all duration-200">
                ▶ 재생
              </button>
              <button className="border border-white/40 text-white px-6 py-3 rounded-lg
                                 hover:bg-white/10 transition-all duration-200">
                + 내 목록
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  )
}

Tip: 클래스 조합 팁

복잡한 컴포넌트는 관심사별로 줄을 나눠 읽기 좋게 작성한다.

레이아웃 → 크기 → 색상 → 상태 순으로 배치하면 유지보수가 편하다.

Warning: 자주 하는 실수

  • hover:scale-105만 쓰면 애니메이션이 없음 → transition-transform duration-300 필수
  • opacity-0 group-hover:opacity-100을 쓸 때 부모에 group 클래스 빠뜨리지 않기
  • fixed 헤더가 있으면 main에 pt-{헤더높이} 필수 (겹침 방지)

댓글 남기기