Type something to search...

06 Tailwind at rule

1. 설명

Tailwind v4는 별도의 JS 설정 파일 없이 CSS 파일 하나로 모든 설정을 관리한다. 핵심 수단이 @ 지시어(at-rule)이다.


2. @import

Tailwind의 모든 기능을 불러오는 진입점이다. 반드시 CSS 파일의 최상단에 위치해야 한다.

1
@import "tailwindcss";

전체를 불러오지 않고 필요한 레이어만 선택적으로 불러올 수도 있다.

1
@import "tailwindcss/preflight"; /* 브라우저 기본 스타일 초기화 */
2
@import "tailwindcss/utilities"; /* 유틸리티 클래스만 */

파일 구조 권장 순서 @import@plugin@source@theme@utility@variant → 컴포넌트


3. @theme

프로젝트 전체에서 사용할 디자인 토큰을 정의한다. CSS 변수 형태로 선언하면 Tailwind가 자동으로 유틸리티 클래스를 생성한다.

3.1. 기본 문법

1
@theme {
2
--{카테고리}-{이름}: {값};
3
}

카테고리가 클래스 이름을 결정한다. 예를 들어 --color-*text-*, bg-*, border-* 등에 모두 적용된다.

3.2. 색상

1
@theme {
2
--color-primary: #f97316;
3
--color-secondary: #6366f1;
4
--color-brand-light: #fff7ed;
5
--color-brand-dark: #431407;
6
}
1
<style type="text/tailwindcss">
2
@theme {
3
--color-primary: #f97316;
4
--color-secondary: #6366f1;
5
--color-brand-light: #fff7ed;
6
--color-brand-dark: #431407;
7
}
8
</style>
9
<div class="bg-primary text-secondary border-brand-light"></div>

3.3. 폰트

1
@theme {
2
--font-sans: "Pretendard", sans-serif;
3
--font-mono: "JetBrains Mono", monospace;
4
}
1
<p class="font-sans">본문 텍스트</p>
2
<code class="font-mono">코드 블록</code>

3.4. 간격 (spacing)

1
@theme {
2
--spacing-18: 4.5rem; /* 72px */
3
--spacing-22: 5.5rem; /* 88px */
4
--spacing-128: 32rem; /* 512px */
5
}
1
<div class="mt-18 px-22 w-128"></div>

3.5. 브레이크포인트

1
@theme {
2
--breakpoint-xs: 480px;
3
--breakpoint-3xl: 1920px;
4
}
1
<div class="xs:flex 3xl:grid"></div>

3.6. 기타 토큰

1
@theme {
2
--shadow-card: 0 4px 24px rgba(0,0,0,0.08);
3
--radius-card: 1.25rem;
4
--animate-spin-slow: spin 3s linear infinite;
5
}
1
<div class="shadow-card rounded-card animate-spin-slow"></div>

3.7. inline 키워드

일반 @theme은 빌드 시 값을 고정한다. inline을 붙이면 CSS 변수 참조를 런타임까지 유지한다. JS로 테마를 동적으로 변경해야 할 때 사용한다.

1
/* 빌드 시 #f97316으로 고정 */
2
@theme {
3
--color-primary: #f97316;
4
}
5
6
/* 런타임에 --brand 값을 참조 */
7
@theme inline {
8
--color-primary: var(--brand);
9
}
1
// 런타임에서 동적 변경 가능
2
document.documentElement.style.setProperty('--brand', '#6366f1');

3.8. 토큰 초기화

기본 제공 토큰을 전부 제거하고 처음부터 정의할 때 *: initial을 사용한다.

1
@theme {
2
--color-*: initial; /* 기본 색상 전체 제거 */
3
--color-primary: #f97316;
4
--color-gray: #6b7280;
5
}

4. @source

Tailwind가 클래스를 스캔할 경로를 추가 지정한다.

1
@source "./src/**/*.{html,js,ts,jsx,tsx,vue,svelte}";
2
@source "../node_modules/@mylib/ui/src";

4.1. 언제 필요한가

  • 외부 패키지(node_modules)에 Tailwind 클래스가 있을 때
  • 모노레포 구조에서 다른 패키지 파일을 참조할 때
  • 자동 감지 범위 밖의 경로를 사용할 때

4.2. 동적 클래스 처리

JS에서 동적으로 생성되는 클래스명은 스캔되지 않는다. inline으로 안전 목록을 직접 명시한다.

1
@source inline("bg-red-500 bg-green-500 bg-blue-500");

5. @utility

Tailwind에 없는 유틸리티 클래스를 직접 만든다. 만든 클래스는 hover:, md:, dark: 등 모든 variant와 조합 가능하다.

5.1. 기본 예시

1
@utility scrollbar-hide {
2
scrollbar-width: none;
3
&::-webkit-scrollbar {
4
display: none;
5
}
6
}
7
8
@utility center {
9
display: flex;
10
align-items: center;
11
justify-content: center;
12
}
13
14
@utility text-balance {
15
text-wrap: balance;
16
}
1
<ul class="scrollbar-hide overflow-x-auto flex gap-4">...</ul>
2
<div class="center w-full h-screen">...</div>
3
<h1 class="text-balance text-4xl font-bold">...</h1>

5.2. variant와 조합

1
<div class="center md:block"></div>
2
<div class="dark:text-balance"></div>
3
<div class="hover:scrollbar-hide"></div>

5.3. 동적 값 수신

--value() 함수를 사용하면 클래스에서 값을 받을 수 있다.

1
@utility tab-* {
2
tab-size: --value(--tab-size, integer);
3
}
1
<pre class="tab-2">...</pre>
2
<pre class="tab-4">...</pre>

6. @variant

Tailwind에 없는 커스텀 variant를 만든다. @slot은 실제 클래스 내용이 삽입되는 자리를 나타낸다.

6.1. 복합 상태

1
@variant hocus {
2
&:hover,
3
&:focus {
4
@slot;
5
}
6
}
7
8
@variant group-hocus {
9
.group:hover &,
10
.group:focus & {
11
@slot;
12
}
13
}
1
<button class="hocus:bg-primary hocus:text-white transition">
2
버튼
3
</button>
4
5
<div class="group">
6
<span class="group-hocus:underline">텍스트</span>
7
</div>

6.2. 미디어쿼리

1
@variant print {
2
@media print { @slot; }
3
}
4
5
@variant landscape {
6
@media (orientation: landscape) { @slot; }
7
}
8
9
@variant retina {
10
@media (-webkit-min-device-pixel-ratio: 2) { @slot; }
11
}
1
<img class="w-full retina:w-1/2" src="...">
2
<nav class="hidden print:block">목차</nav>

6.3. 속성 기반

1
@variant selected {
2
&[data-selected="true"] { @slot; }
3
}
4
5
@variant aria-expanded {
6
&[aria-expanded="true"] { @slot; }
7
}
1
<li class="selected:bg-primary" data-selected="true">항목</li>
2
<button class="aria-expanded:rotate-180" aria-expanded="true">▼</button>

7. @plugin

외부 Tailwind 플러그인 또는 직접 만든 JS 플러그인을 불러온다.

1
@plugin "@tailwindcss/typography";
2
@plugin "@tailwindcss/forms";
3
@plugin "./plugins/my-plugin.js";

7.1. 공식 플러그인 사용 예시

1
<article class="prose prose-lg">
2
<h1>제목</h1>
3
<p>본문 내용...</p>
4
</article>

7.2. 커스텀 플러그인 작성

plugins/custom.js
1
export default function({ addUtilities, addVariant }) {
2
addUtilities({
3
'.flex-center': {
4
display: 'flex',
5
alignItems: 'center',
6
justifyContent: 'center',
7
}
8
});
9
10
addVariant('not-last', '&:not(:last-child)');
11
}
1
@plugin "./plugins/custom.js";
1
<div class="flex-center not-last:border-b">...</div>

8. @config

기존 tailwind.config.js를 CSS에서 참조한다. v4로 점진적으로 마이그레이션할 때 사용하며, 전환이 완료되면 제거한다.

1
@import "tailwindcss";
2
@config "../../tailwind.config.js";

@config@theme이 충돌하면 @theme이 우선한다.


9. @apply

CSS 규칙 안에서 Tailwind 유틸리티 클래스를 직접 적용한다.

1
.btn {
2
@apply inline-flex items-center justify-center;
3
@apply px-4 py-2 rounded-lg font-semibold transition-colors;
4
}
5
6
.btn-primary {
7
@apply btn bg-primary text-white hover:bg-orange-600;
8
}
9
10
.btn-outline {
11
@apply btn border border-primary text-primary;
12
@apply hover:bg-primary hover:text-white;
13
}
14
15
.card {
16
@apply bg-white rounded-card shadow-card p-6 space-y-4;
17
}
18
19
.input {
20
@apply w-full px-3 py-2 rounded-lg border border-gray-300;
21
@apply focus:outline-none focus:ring-2 focus:ring-primary;
22
@apply placeholder:text-gray-400;
23
}
1
<button class="btn-primary">확인</button>
2
<button class="btn-outline">취소</button>
3
4
<div class="card">
5
<input class="input" placeholder="이름을 입력하세요">
6
</div>

남용 주의@apply를 과도하게 사용하면 클래스만 보고 스타일을 파악하는 Tailwind의 장점이 사라진다. 반복적으로 조합되는 공통 컴포넌트에만 제한적으로 사용하는 것이 권장된다.


10. 전체 구조 예시

실제 프로젝트에서 CSS 파일을 구성하는 전형적인 형태이다.

src/styles/global.css
1
/* 1. 진입점 */
2
@import "tailwindcss";
3
4
/* 2. 플러그인 */
5
@plugin "@tailwindcss/typography";
6
7
/* 3. 스캔 경로 */
8
@source "./src/**/*.{astro,html,js,ts,jsx,tsx}";
9
10
/* 4. 디자인 토큰 */
11
@theme {
12
--color-primary: #f97316;
13
--color-secondary: #6366f1;
14
--font-sans: "Pretendard", sans-serif;
15
--spacing-18: 4.5rem;
16
--radius-card: 1.25rem;
17
--shadow-card: 0 4px 24px rgba(0,0,0,0.08);
18
--breakpoint-xs: 480px;
19
}
20
21
/* 5. 커스텀 유틸리티 */
22
@utility scrollbar-hide {
23
scrollbar-width: none;
24
&::-webkit-scrollbar { display: none; }
25
}
26
27
@utility center {
28
display: flex;
29
align-items: center;
30
justify-content: center;
31
}
32
33
/* 6. 커스텀 variant */
34
@variant hocus {
35
&:hover, &:focus { @slot; }
36
}
37
38
@variant print {
39
@media print { @slot; }
40
}
41
42
/* 7. 컴포넌트 */
43
.btn {
44
@apply inline-flex items-center justify-center;
45
@apply px-4 py-2 rounded-lg font-semibold transition-colors;
46
}