Tailwind CSS @theme 사용법: 변수와 디자인 토큰 구분하기

2026.04.29·수정 2026.09.13·약 20분·작성: 해비·블로그 소개

이 글에서 정리하는 내용

Tailwind CSS v4 기준으로 Theme Variables와 Design Token을 구분해 정리합니다. @theme는 단순히 CSS 변수를 모아두는 문법이 아니라, 프로젝트에서 사용할 유틸리티 클래스의 기준이 됩니다. 버튼 색상, 카드 모서리, 공통 그림자처럼 반복되는 UI 값을 어디까지 토큰으로 분리할지 함께 살펴봅니다.

Tailwind 클래스를 쓰다 보면 기준이 흩어지는 순간

Tailwind @theme 사용법: 변수와 디자인 토큰 차이 핵심 개념을 설명하는 첫 번째 본문 이미지

Tailwind를 처음 사용할 때는 기본 유틸리티만으로도 화면이 빠르게 잡힙니다. 버튼은 bg-blue-600, 글자는 text-gray-800, 카드는 rounded-xl shadow-sm, 간격은 p-5 gap-4처럼 바로 붙이면 됩니다. 한두 개의 화면을 만드는 단계에서는 이 방식이 가장 단순합니다.

문제는 비슷한 UI가 여러 화면에 퍼진 뒤에 드러납니다. 상품 카드에서는 rounded-xl을 쓰고, 관리자 카드에서는 rounded-2xl을 쓰고, 모달에서는 rounded-lg를 쓰기 시작합니다. 버튼도 어떤 곳은 bg-blue-600, 어떤 곳은 bg-sky-600, 또 다른 곳은 bg-indigo-600으로 갈라집니다. 각각은 틀린 코드가 아니지만, 나중에 브랜드 색상을 바꾸거나 카드 스타일을 통일하려고 하면 기준이 어디에 있었는지 찾기 어려워집니다.

이 지점에서 Design Token이 필요해집니다. 토큰은 클래스를 짧게 줄이는 장치가 아니라, 프로젝트 안에서 반복되는 시각적 결정을 이름으로 남기는 기준입니다. Tailwind v4에서는 이 기준을 CSS 안의 @theme로 정의할 수 있습니다.

처음에는 문제가 없어 보이는 코드

부분 예제 — 앞뒤 설명에 해당하는 코드만 적용하세요. 다른 예제와 합친 전체 프로젝트가 아닙니다.

<button
  class="rounded-xl bg-blue-600 px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-blue-700"
>
  저장하기
</button>
<article class="rounded-xl border border-gray-200 bg-white p-5 shadow-sm">
  <h3 class="text-lg font-bold text-gray-900">상품명</h3>
  <p class="mt-2 text-sm text-gray-600">상품 설명이 들어갑니다.</p>
</article>

이 코드는 그대로 써도 화면은 나옵니다. 다만 blue-600이 브랜드의 대표 색상인지, 해당 버튼에서만 잠깐 고른 색인지 코드만 보고 구분하기 어렵습니다. rounded-xl도 마찬가지입니다. 카드의 표준 radius인지, 해당 컴포넌트에서만 쓰는 임시 값인지 판단하려면 다른 파일까지 뒤져야 합니다.

Design Token은 예쁜 변수명이 아니라 반복 기준이다

Design Token을 처음 보면 primary, secondary, danger 같은 이름을 붙이는 작업처럼 보입니다. 하지만 이름만 바꾼다고 토큰이 되는 것은 아닙니다. 토큰의 역할은 “이 프로젝트에서 이 값은 어떤 의미로 반복되는가”를 코드에 남기는 것입니다.

예를 들어 #2563eb라는 색상이 있다고 해보겠습니다. 이 색상은 단순한 파란색일 수도 있고, 브랜드 대표 색상일 수도 있고, 저장 버튼의 배경색일 수도 있습니다. 셋은 비슷해 보이지만 수정 기준이 다릅니다. 색상 자체가 바뀌는 문제인지, 브랜드 톤이 바뀌는 문제인지, 버튼 컴포넌트의 상태 스타일이 바뀌는 문제인지 분리해서 봐야 합니다.

구분 예시 역할
원시 값 #2563eb 색상 자체
의미 값 brand, action, danger 프로젝트에서 쓰이는 목적
컴포넌트 기준 button, card, badge 특정 UI 요소의 표준 스타일

작은 프로젝트에서는 이 셋을 모두 엄격하게 나누지 않아도 됩니다. 오히려 처음부터 원시 토큰, 의미 토큰, 컴포넌트 토큰을 모두 만들면 이름만 늘고 실제 작업 속도는 떨어집니다. 먼저 반복되는 값을 찾는 쪽이 낫습니다. 버튼 색상, 카드 radius, 공통 shadow, 대표 font family처럼 여러 화면에서 다시 등장하는 값이 첫 번째 후보입니다.

토큰으로 볼 만한 값

부분 예제 — 앞뒤 설명에 해당하는 코드만 적용하세요. 다른 예제와 합친 전체 프로젝트가 아닙니다.

@import "tailwindcss";
@theme {
  --color-brand-50: #eff6ff;
  --color-brand-600: #2563eb;
  --color-brand-700: #1d4ed8;
  --radius-card: 1rem;
  --shadow-card: 0 1px 3px rgb(15 23 42 / 0.08);
}

여기서 --color-brand-600은 단순한 파란색이 아니라 브랜드 강조색으로 쓰겠다는 결정입니다. --radius-card는 카드마다 rounded-xl을 반복해서 붙이는 대신, 카드의 모서리 기준을 따로 남긴 값입니다. 카드 디자인을 조금 더 각지게 바꾸거나 그림자 톤을 낮춰야 할 때, 수정할 위치가 자연스럽게 좁혀집니다.

Tailwind v4에서 Theme Variables가 하는 일

Tailwind v4에서 @theme 안에 정의하는 값은 Theme Variables입니다. 모양만 보면 CSS 변수와 비슷합니다. 실제로 CSS 변수처럼 참조할 수도 있습니다. 하지만 Tailwind 입장에서 @theme는 일반 :root 변수보다 더 큰 역할을 합니다.

@theme--color-brand-600을 정의하면 Tailwind는 이 값을 색상 namespace에 속한 theme variable로 봅니다. 그래서 bg-brand-600, text-brand-600, border-brand-600 같은 유틸리티를 사용할 수 있게 됩니다. --radius-card를 정의하면 rounded-card처럼 쓸 수 있고, --shadow-card를 정의하면 shadow-card가 됩니다.

@theme로 유틸리티 기준 만들기

부분 예제 — 앞뒤 설명에 해당하는 코드만 적용하세요. 다른 예제와 합친 전체 프로젝트가 아닙니다.

@import "tailwindcss";
@theme {
  --color-brand-600: #2563eb;
  --color-brand-700: #1d4ed8;
  --radius-card: 1rem;
  --shadow-card: 0 1px 3px rgb(15 23 42 / 0.08);
}

부분 예제 — 앞뒤 설명에 해당하는 코드만 적용하세요. 다른 예제와 합친 전체 프로젝트가 아닙니다.

<button
  class="rounded-lg bg-brand-600 px-4 py-2 text-sm font-semibold text-white hover:bg-brand-700"
>
  저장하기
</button>
<article class="rounded-card border border-gray-200 bg-white p-5 shadow-card">
  <h3 class="text-lg font-bold text-gray-900">상품명</h3>
  <p class="mt-2 text-sm text-gray-600">상품 설명이 들어갑니다.</p>
</article>

이렇게 바꾸면 클래스 개수가 크게 줄어드는 것은 아닙니다. 대신 클래스가 가리키는 기준이 달라집니다. bg-brand-600은 “파란색 하나를 골랐다”가 아니라 “이 프로젝트의 브랜드 강조색을 사용한다”는 의미를 갖습니다. rounded-card도 단순한 radius 값보다 카드 UI의 표준 모서리 값이라는 흔적을 남깁니다.

namespace를 맞춰야 클래스가 생긴다

Tailwind theme variables는 이름 앞부분의 namespace가 중요합니다. --color-*는 색상 유틸리티와 연결되고, --font-*는 font family 유틸리티, --text-*는 글자 크기 유틸리티, --spacing-*은 간격과 크기 계열 유틸리티, --radius-*는 border radius 유틸리티와 연결됩니다.

예를 들어 --brand-color-main처럼 자유롭게 이름을 지으면 일반 CSS 변수처럼 볼 수는 있어도 Tailwind 색상 유틸리티와 기대한 방식으로 연결되지 않습니다. Tailwind에서 bg-brand-600 같은 클래스를 만들고 싶다면 --color-brand-600처럼 namespace를 맞춰야 합니다.

부분 예제 — 앞뒤 설명에 해당하는 코드만 적용하세요. 다른 예제와 합친 전체 프로젝트가 아닙니다.

@theme {
  --color-brand-600: #2563eb;
  --font-display: "Pretendard", sans-serif;
  --text-page-title: 2rem;
  --radius-card: 1rem;
  --shadow-panel: 0 8px 24px rgb(15 23 42 / 0.08);
}

위 값들은 각각 bg-brand-600, font-display, text-page-title, rounded-card, shadow-panel처럼 사용할 수 있는 기준이 됩니다. 원하는 이름을 아무렇게나 붙이는 것이 아니라, Tailwind가 이해하는 namespace 안에서 프로젝트 전용 이름을 설계하는 방식입니다.

@theme와 :root는 언제 나눠야 할까

@theme:root는 둘 다 CSS 변수처럼 보이기 때문에 헷갈리기 쉽습니다. 기준은 “Tailwind 유틸리티로 사용할 값인가”입니다. 유틸리티 클래스로 쓰고 싶은 값은 @theme에 둡니다. CSS 안에서만 계산하거나 특정 컴포넌트 내부에서만 쓰는 값은 :root나 선택자 내부 변수로 둬도 충분합니다.

구분 사용하는 경우 예시
@theme Tailwind 유틸리티 클래스로 쓰고 싶은 값 --color-brand-600, --radius-card
:root CSS 안에서만 재사용할 일반 변수 --header-height, --overlay-alpha
컴포넌트 선택자 내부 해당 컴포넌트에서만 필요한 임시 계산값 --card-image-ratio, --local-gap

예를 들어 --header-height는 레이아웃 계산에는 필요하지만 h-header 같은 Tailwind 클래스로 계속 쓸 값이 아닐 수 있습니다. 이런 값까지 전부 @theme에 올리면 theme가 실제 디자인 토큰과 임시 레이아웃 변수로 뒤섞입니다.

부분 예제 — 앞뒤 설명에 해당하는 코드만 적용하세요. 다른 예제와 합친 전체 프로젝트가 아닙니다.

@import "tailwindcss";
@theme {
  --color-brand-600: #2563eb;
  --radius-card: 1rem;
  --shadow-card: 0 1px 3px rgb(15 23 42 / 0.08);
}
:root {
  --header-height: 64px;
  --page-inline-padding: 20px;
}
.admin-layout {
  min-height: calc(100vh - var(--header-height));
  padding-inline: var(--page-inline-padding);
}

이 구조에서는 Tailwind 유틸리티로 반복해서 쓰는 디자인 기준은 @theme에 있고, 레이아웃 계산에 필요한 일반 변수는 :root에 있습니다. 나중에 파일을 다시 볼 때도 “이 값은 클래스 API로 쓰는 값인지, CSS 계산용 값인지” 구분할 수 있습니다.

디자인 토큰을 너무 많이 만들면 생기는 문제

디자인 토큰을 알게 되면 모든 값을 이름 붙이고 싶어질 수 있습니다. 하지만 Tailwind에서는 기본 스케일 자체가 이미 촘촘합니다. p-4, gap-6, text-sm, rounded-lg, shadow-sm 같은 값은 많은 프로젝트에서 그대로 써도 무리가 없습니다.

처음부터 spacing 전체를 --spacing-section, --spacing-card, --spacing-list, --spacing-button처럼 나누면 오히려 판단해야 할 이름이 늘어납니다. 토큰이 많다고 시스템이 좋아지는 것은 아닙니다. 실제 화면에서 반복되고, 바뀔 가능성이 있고, 프로젝트 안에서 의미가 공유되는 값이 토큰 후보입니다.

토큰화가 애매한 경우

부분 예제 — 앞뒤 설명에 해당하는 코드만 적용하세요. 다른 예제와 합친 전체 프로젝트가 아닙니다.

@theme {
  --spacing-card-small: 0.875rem;
  --spacing-card-normal: 1rem;
  --spacing-card-large: 1.125rem;
  --spacing-card-extra: 1.25rem;
}

이런 값은 이름은 많지만 기준이 선명하지 않습니다. small, normal, large, extra가 실제 화면에서 어떤 차이를 만드는지 설명하기 어렵다면, 기본 spacing scale을 쓰는 쪽이 더 단순합니다. 반대로 섹션 상하 여백처럼 페이지 전체 리듬을 결정하는 값이라면 토큰으로 분리할 이유가 생깁니다.

토큰화할 이유가 선명한 경우

부분 예제 — 앞뒤 설명에 해당하는 코드만 적용하세요. 다른 예제와 합친 전체 프로젝트가 아닙니다.

@theme {
  --spacing-section-y: 5rem;
  --radius-card: 1rem;
  --shadow-card: 0 1px 3px rgb(15 23 42 / 0.08);
  --color-brand-600: #2563eb;
}

이 값들은 화면 전체의 인상에 영향을 줍니다. 브랜드 색상, 카드 모서리, 카드 그림자, 섹션 간격처럼 여러 컴포넌트에서 반복되는 값은 나중에 디자인 톤을 바꿀 때 수정 기준이 됩니다.

작은 프로젝트에서 시작하는 토큰 정리 순서

Tailwind @theme 사용법: 변수와 디자인 토큰 차이 적용 흐름을 설명하는 두 번째 본문 이미지

작은 프로젝트라면 처음부터 완성된 디자인 시스템을 만들 필요는 없습니다. Tailwind의 기본값을 버리고 모든 것을 커스텀하려고 하면, 오히려 Tailwind를 쓰는 장점이 줄어듭니다. 시작 순서는 좁게 잡는 것이 좋습니다.

브랜드 색상부터 분리하기

가장 먼저 분리할 만한 값은 브랜드 색상입니다. 색상은 버튼, 링크, 배지, 활성 상태, 포커스 링 등 여러 곳에 반복됩니다. blue, sky, indigo처럼 실제 색상 이름으로 남겨도 되지만, 프로젝트의 대표 강조색이라면 brand로 바꾸는 순간 수정 기준이 더 선명해집니다.

부분 예제 — 앞뒤 설명에 해당하는 코드만 적용하세요. 다른 예제와 합친 전체 프로젝트가 아닙니다.

@theme {
  --color-brand-50: #eff6ff;
  --color-brand-100: #dbeafe;
  --color-brand-600: #2563eb;
  --color-brand-700: #1d4ed8;
}

카드와 버튼 기준값 분리하기

카드와 버튼은 대부분의 화면에서 반복됩니다. 특히 관리자 화면이나 쇼핑몰 UI처럼 카드가 여러 개 쌓이는 구조에서는 radius와 shadow가 조금만 달라도 화면이 산만해집니다. 이때 rounded-card, shadow-card처럼 기준을 만들면 컴포넌트가 늘어나도 시각적 리듬이 덜 흔들립니다.

부분 예제 — 앞뒤 설명에 해당하는 코드만 적용하세요. 다른 예제와 합친 전체 프로젝트가 아닙니다.

<section class="grid gap-4 md:grid-cols-3">
  <article class="rounded-card border border-gray-200 bg-white p-5 shadow-card">
    <span class="text-sm font-medium text-brand-600">NEW</span>
    <h3 class="mt-2 text-lg font-bold text-gray-900">카드 제목</h3>
    <p class="mt-2 text-sm text-gray-600">반복되는 카드 설명입니다.</p>
  </article>
</section>

spacing은 무리해서 전부 바꾸지 않기

간격은 토큰화 욕심이 가장 많이 생기는 영역입니다. 하지만 Tailwind의 기본 spacing scale은 유틸리티 중심 작업에 맞게 이미 준비되어 있습니다. 모든 p-4, gap-6, mt-8을 커스텀 이름으로 바꾸기보다, 섹션 간격이나 레이아웃 최대 폭처럼 반복 기준이 확실한 값부터 분리하는 쪽이 현실적입니다.

공유할 값은 별도 theme 파일로 분리하기

프로젝트가 커져서 웹, 관리자, 랜딩 페이지가 같은 브랜드 기준을 써야 한다면 theme 파일을 분리할 수 있습니다. 이때 @theme를 한 파일에 모아두고 각 진입 CSS에서 import하면 여러 화면이 같은 토큰을 바라보게 됩니다.

부분 예제 — 앞뒤 설명에 해당하는 코드만 적용하세요. 다른 예제와 합친 전체 프로젝트가 아닙니다.

@import "tailwindcss";
@import "./theme/brand.css";

처음부터 패키지 구조까지 만들 필요는 없습니다. 다만 브랜드 색상과 카드 기준처럼 여러 화면이 같이 쓰는 값이 생겼다면, 하나의 CSS 파일로 분리해두는 것만으로도 수정 위치가 명확해집니다.

한 토큰을 바꾸어 영향 범위를 확인합니다

본문 @theme 예제의 색상 토큰 하나를 바꾸고 그 토큰을 쓰는 두 요소를 비교합니다. 이어서 :root의 일반 변수를 바꾸고 생성되는 유틸리티와 사용 위치를 구분하세요.

풀이 기준과 확인 결과

테마 네임스페이스의 변수는 대응 유틸리티와 연결됩니다. 일반 CSS 변수는 선언만으로 모든 종류의 Tailwind 클래스를 만드는 것은 아닙니다.

변경한 토큰을 쓰는 요소만 함께 바뀌는지 확인합니다. 단 한 요소의 예외 값까지 공통 토큰으로 올리지 않습니다.

정리: 토큰은 클래스를 줄이는 도구가 아니라 수정 기준을 남기는 도구다

Tailwind의 Theme Variables를 단순히 “CSS 변수처럼 쓰는 기능”으로만 보면 :root와 차이가 흐려집니다. Tailwind v4의 @theme는 디자인 토큰을 정의하면서, 동시에 어떤 유틸리티 클래스가 프로젝트에 존재할지 정하는 기준입니다.

Design Token은 이름을 많이 만드는 작업이 아닙니다. 버튼 색상, 카드 모서리, 공통 shadow, 대표 폰트처럼 여러 화면에서 반복되고 나중에 바뀔 가능성이 있는 값을 먼저 분리하는 것이 출발점입니다. 반대로 한 컴포넌트 안에서만 쓰는 임시 계산값이나 레이아웃 보조값은 :root나 컴포넌트 내부 변수로 두는 쪽이 더 단순합니다.

다음에 Tailwind로 UI를 만들 때는 클래스를 줄일 수 있는지보다, 이 값이 프로젝트의 기준으로 남을 만한지 먼저 확인해야 합니다. bg-brand-600, rounded-card, shadow-panel 같은 이름은 짧아서 쓰는 것이 아니라, 나중에 같은 화면을 다시 고칠 때 기준점으로 돌아오기 위해 남겨두는 이름입니다.

토큰이 실제 유틸리티 클래스와 어떻게 연결되는지 복습하려면 Tailwind CSS 기본 클래스 사용법 글을 함께 참고하면 좋습니다.

참고 자료

Tailwind CSS v4의 theme variables, @theme, namespace, :root와의 차이, theme variable 공유 방식은 Tailwind CSS 공식 문서의 Theme variables 설명을 기준으로 정리했습니다.

이 글이 도움이 되었나요?

조회 중

Tailwind CSS 학습 순서

필수 15개 · 전체 22개

읽음 기록 관리

전체 과정 목차 (22개)
  1. 필수 길잡이 · Tailwind CSS 실전 로드맵: 기본·반응형·상태·동적 클래스 학습 순서
  2. 필수 학습 · Tailwind CSS 기본 클래스 사용법: text font bg spacing 익히기
  3. 필수 학습 · Tailwind border flex 사용법: 레이아웃 기본 클래스 기준
  4. 필수 학습 · Tailwind CSS Preflight 기준: 기본 스타일 초기화가 생기는 이유
  5. 필수 학습 · Tailwind CSS Grid 실무 레이아웃 정리: 카드 목록부터 대시보드까지
  6. 필수 학습 · Tailwind CSS 반응형 클래스 사용법: sm md lg 기준 잡기
  7. 필수 학습 · Tailwind CSS 상태 variant 사용법: hover focus aria data 기준 잡기
  8. 필수 학습 · Tailwind CSS group peer has 차이: 상태 기준으로 고르는 방법
  9. 필수 학습 · Tailwind CSS dark 사용법: 다크 모드 구현 기준 잡기
  10. 필수 학습 · Tailwind CSS arbitrary value 차이: 대괄호 문법 사용 기준 잡기
  11. 선택 참고 · Tailwind CSS 임의 값 공백 처리: 대괄호 문법이 깨질 때 해결하기
  12. 필수 학습 · Tailwind CSS @theme 사용법: 변수와 디자인 토큰 구분하기 현재 글
  13. 필수 학습 · Tailwind Container Query 사용법: 부모 너비 기준 반응형 처리
  14. 필수 학습 · React Tailwind className 정리: 조건부·variant·가독성 기준
  15. 필수 학습 · Tailwind CSS 동적 클래스 해결: 감지 원리와 @source 사용법
  16. 필수 학습 · Tailwind CSS @apply 사용 기준: @utility와 custom variant 구분하기
  17. 선택 참고 · Tailwind CSS transition, animation, motion-reduce 사용 기준 정리
  18. 선택 참고 · Tailwind CSS v4.1 유틸리티 정리: text-shadow와 mask 사용하기
  19. 선택 참고 · Radix UI와 shadcn/ui 차이: 컴포넌트를 고를 때 헷갈리는 기준 정리
  20. 선택 참고 · shadcn/ui No import alias found 오류 해결: tsconfig 설정
  21. 선택 참고 · Tailwind CSS flex 레이아웃 깨질 때 확인할 것
  22. 선택 참고 · Tailwind CSS 클래스 적용 안 됨 해결 순서

새 글 받아보기

RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.

RSS 피드 구독하기

댓글 남기기