
Next.js 프로젝트를 세팅하면서 가장 헷갈렸던 부분 중 하나가
globals.css와tailwind.config.ts였다. 둘 다 전역에 스타일을 적용할 수 있는데, 무엇을 어디에 두어야 할지 정리가 필요했다.
나는 이렇게 생각했다.
- globals.css: 전역으로 CSS를 먹이는 곳
- tailwind.config.ts: 이것도 전역으로 먹일 수 있는 곳
둘 다 “전역 적용”이라는 점에서 비슷해 보인다. 하지만 조금 더 깊게 들어가 보니 성격이 달랐다.
globals.css — 실제 CSS
globals.css는 브라우저가 직접 읽는 CSS 파일이다.
여기에reset, Tailwind 지시어, body 기본값등을 적으면 모든 페이지에 바로 적용된다.예를 들어
@import "reset-css/reset.css"; @tailwind base; @tailwind components; @tailwind utilities; body { @apply font-sans bg-white text-gray-900; line-height: 1.5; letter-spacing: -0.01em; }👉 즉, 전역으로 바로 먹이는 실제 CSS 코드다.
tailwind.config.ts — 전역 설계도반대로
tailwind.config.ts는 CSS가 아니라 설정 파일이다.
여기에색상, 폰트, spacing 단위등을 정의하면 Tailwind가 빌드 과정에서 새로운 유틸리티 클래스를 만들어준다.예를 들어:
theme: { extend: { colors: { primary: "#06c", }, fontFamily: { sans: ["Pretendard", "ui-sans-serif", "system-ui"], }, }, }이렇게 정의해두면 어디서든
class="text-primary font-sans"처럼 쓸 수 있다.
👉 즉, 전역 스타일을 “설계”해 두는 곳이다. 실제 적용은Tailwind가 생성한 클래스가 담당한다.
둘 다 전역에 영향을 주지만, 차이점은 적용 방식이다.
globals.css→ 브라우저에 직접 적용되는 전역 CSStailwind.config.ts→ Tailwind가 유틸리티 클래스로 변환하는 전역 설계도결국 나는 이렇게 사용하기로 했다.
reset, body 기본값 같은 최소 전역 스타일은globals.css에폰트, 컬러 팔레트 같은 디자인 토큰은tailwind.config.ts에
프로젝트 세팅을 하면서 전역 스타일 관리 방식을 정리하다가, 추가로 리서치를 해봤다. 리서치 자료
그 과정에서Tailwind가 최근 v4로 업데이트되었다는 걸 알게 되었다. 이번 버전에서는 전역 스타일을 관리하는 방식이 훨씬 단순해졌다.이전(v3)까지는
globals.css와tailwind.config.ts두 파일을 나눠서 관리해야 했다. 하지만 v4부터는 하나의 CSS 파일에 모든 걸 몰아넣는 방식이 가능해졌다.
기존에는 전역 스타일과 디자인 토큰을 이렇게 분리했다.
globals.css→ reset, Tailwind 지시어, body 전역 스타일tailwind.config.ts→ 색상, 폰트, spacing 같은 디자인 토큰이 구조는 체계적이지만, 파일이 분리되다 보니 초반에는 다소 헷갈리기도 했다.
리서치하면서 확인한 가장 큰 변화는 올인원 관리였다.
- Tailwind 불러오기: 한 줄로 import
- 디자인 토큰 정의: CSS 안에서 바로 선언 가능
- 전역 스타일: reset과 함께 base 확장으로 처리
즉, 더 이상 설정 파일을 따로 둘 필요 없이 CSS 한 파일만으로도 프로젝트 전역 스타일을 컨트롤할 수 있게 된 것이다.
Tailwind에는 기본적으로 Preflight라는modern reset이 들어 있어, 별도의reset 패키지를 쓰지 않아도 된다.
필요한 경우에는 전역 스타일 레이어에서 원하는 부분만 덮어쓰면 된다.
- v3까지:
globals.css+tailwind.config.ts로 나눠 관리- v4부터:
globals.css하나로 import, 토큰, 전역 스타일까지 관리 가능- 장점: 단순함, 진입장벽 낮음, 스타일 관리가 한눈에 보임
- 단점: 대규모 프로젝트나 모노레포에서는 여전히 분리된 설정 파일이 유리할 수 있음
:root vs @theme inline — 뭐가 다르고, 언제 써야 할까?Tailwind v4를 쓰다 보면
globals.css안에 이런 코드가 생긴다.:root { --background: #ffffff; --foreground: #171717; } @theme inline { --color-background: var(--background); --color-foreground: var(--foreground); }처음 보면 “둘 다 색을 정의하는데, 도대체 뭐가 다른 거야?” 싶다.
이 둘은 비슷해 보이지만, 역할이 완전히 다르다.
🧩 1)
:root는 ‘일반적인 CSS 변수’
:root는 말 그대로 CSS의 전역 변수다.
사이트 전체에서var(--background)처럼 직접 불러다 쓸 수 있다.:root { --background: #ffffff; --foreground: #171717; } body { background: var(--background); color: var(--foreground); }이렇게 하면 Tailwind를 몰라도 순수 CSS만으로 색을 적용할 수 있다.
하지만 문제는 — Tailwind가 제공하는bg-background,text-foreground같은 유틸리티 클래스는 이 변수를 모르고 있다는 점이다.
즉,
✅body { background: var(--background) }→ O
❌<div class="bg-background">→ X (유틸 자체가 생성되지 않음)
🧭 2)
@theme inline은 Tailwind 전용 “색 이름표”Tailwind v4에서는
@theme inline을 통해 CSS 변수와 Tailwind 유틸리티를 연결한다.
쉽게 말해,
“이 변수 이름으로 Tailwind 유틸(bg-,text-,border-등)을 만들어줘”
라고 Tailwind에게 알려주는 구간이다.@theme inline { --color-background: var(--background); --color-foreground: var(--foreground); }이 코드가 있어야 Tailwind가
👉bg-background,text-foreground,border-border같은 클래스를 생성한다.
🪄 3) 어떤 방식을 쓰면 좋을까?
✅ 방법 A — 가장 권장 (원시 변수 + 매핑)
원시 변수(
:root)를 두고,@theme inline에서 Tailwind용 이름으로 연결해주는 방식이다.
이 구조가 가장 유연하고, 다크모드 전환에도 강하다.@import "tailwindcss"; /* 1) 원시 변수 선언 */ :root { --background: #ffffff; --foreground: #171717; } @media (prefers-color-scheme: dark) { :root { --background: #0a0a0a; --foreground: #ededed; } } /* 2) Tailwind 유틸용 의미 토큰 매핑 */ @theme inline { --color-background: var(--background); --color-foreground: var(--foreground); } /* 3) 직접 사용도 가능 */ body { background: var(--background); color: var(--foreground); }📌 이 방식의 장점
- Tailwind 유틸(
bg-background,text-foreground) + 일반 CSS 둘 다 동작- 다크모드 전환도 자연스럽게 가능
- 색 교체가 쉬움 (한 곳만 수정하면 전체 반영)
✅ 방법 B — 가장 간단 (커스텀 토큰을 바로 정의)
Tailwind 유틸만 쓸 예정이거나, 다크모드를 아예 안 쓴다면
@theme inline안에 색을 바로 정의해도 된다.@import "tailwindcss"; @theme inline { --color-background: #fafafa; --color-foreground: #111827; --color-primary: #06c; --color-primary-foreground: #ffffff; }📌 이 방식의 장점
- 설정이 단순하고 빠름
globals.css하나로 끝- 다크모드나 외부 변수 연결이 필요 없는 경우에 적합
⚠️ 방법 C —
:root만 쓰는 경우 (비추천)Tailwind의
bg-*,text-*유틸은 생성되지 않는다.
직접 CSS에서는 동작하지만, 유틸리티를 전혀 못 쓴다.:root { --background: #fff; } body { background: var(--background); /* ✅ 가능 */ } /* <div class="bg-background"> ❌ 동작 안 함 */
🧱 4) 정리 요약
구분 역할 Tailwind 유틸 가능 다크모드 대응 사용 난이도 :root일반 CSS 변수 ❌ ⭕ 가능 (CSS 수준) 가장 쉬움 @theme inlineTailwind용 토큰 (색 이름표) ⭕ ⭕ 약간 설정 필요 둘 다 조합 (추천) 원시 변수 + 유틸 매핑 ⭕ ⭕ ⭐️ 균형형 (추천) .
📚 5) 보너스:
@layer는 왜 쓰는 걸까?Tailwind에서는
@layer가 스타일의 “적용 우선순서”를 관리하는 구조다.
쉽게 말해, “CSS가 겹칠 때 누가 먼저 적용될지”를 Tailwind에게 알려주는 개념이다.@layer base { /* 브라우저 기본 스타일을 덮어쓰는 전역 설정 */ html, body { font-family: Pretendard, system-ui, sans-serif; color: var(--color-foreground); background: var(--color-background); } } @layer components { /* 프로젝트 내부에서 만든 공통 컴포넌트 스타일 */ .card { @apply bg-card text-card-foreground rounded-lg shadow; } } @layer utilities { /* tailwind 유틸처럼 바로 적용되는 간단한 클래스 */ .t-14-b { font-size: 1.4rem; font-weight: 700; } }Tailwind는 내부적으로 CSS를 세 구역으로 분리해서 처리한다.
Layer 용도 우선순위 base 브라우저 기본값 수정 (reset, 전역 폰트 등) 가장 낮음 components 재사용 가능한 컴포넌트 스타일 중간 utilities .p-4,.text-sm처럼 바로 적용되는 클래스가장 높음 즉,
- 전역 설정(
@layer base)은 항상 먼저 읽히고,- 컴포넌트(
@layer components)가 그 위에 올라가며,- 유틸리티(
@layer utilities)가 제일 나중에 덮어쓴다.
그래서@layer를 쓰면 CSS가 겹쳐도
“어떤 스타일이 우선인지” Tailwind가 정확하게 판단할 수 있다.
💬 한 줄 요약
:root는 CSS 전역 변수,
@theme inline은 Tailwind가 유틸을 만들기 위한 토큰 선언,
@layer는 CSS가 적용되는 순서를 정리하는 구획이다.이 세 가지를 함께 쓰면 —
전역 색 체계, 유틸 생성, 그리고 우선순위까지 깔끔하게 통제할 수 있다.