๐ŸŽ›๏ธ Tailwind 9์žฅ: ํ…Œ๋งˆ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•

2026๋…„ 3์›” 5์ผ ์ˆ˜์ •๋จ

๐Ÿ“‹ ๊ฐœ์š”

@theme ๋””๋ ‰ํ‹ฐ๋ธŒ์™€ ๋””์ž์ธ ํ† ํฐ โ€” ๋ธŒ๋žœ๋“œ ์ปฌ๋Ÿฌ, ํฐํŠธ, ์ปค์Šคํ…€ ์Šค์ผ€์ผ์„ Tailwind ์‹œ์Šคํ…œ์— ํ†ตํ•ฉํ•˜๊ธฐ

๐Ÿ“‹ ๋ชฉ์ฐจ


๐Ÿ“Œ ์ด ๋ฌธ์„œ๋ฅผ ์ฝ๊ธฐ ์ „์—

โฑ๏ธ ์˜ˆ์ƒ ์ฝ๊ธฐ ์‹œ๊ฐ„: 15๋ถ„

๐ŸŽฏ ์ด ๋ฌธ์„œ๋ฅผ ๋‹ค ์ฝ์œผ๋ฉด ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ

  • @theme ๋””๋ ‰ํ‹ฐ๋ธŒ๋กœ ์ปค์Šคํ…€ ์ƒ‰์ƒ, ํฐํŠธ, ๊ฐ„๊ฒฉ์„ Tailwind ์— ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค
  • ๋ธŒ๋žœ๋“œ ์ปฌ๋Ÿฌ๋ฅผ bg-brand-500, text-brand-600 ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค
  • ๋””์ž์ธ ํ† ํฐ๊ณผ Tailwind ํด๋ž˜์Šค ์‹œ์Šคํ…œ์„ ์—ฐ๊ฒฐํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ๋‹ค

๐Ÿ—บ๏ธ ์ด ๋ฌธ์„œ์˜ ๋ฐฐ๊ฒฝ ์„ธ๊ณ„๊ด€: '์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ'

  • ๐ŸŽจ ์˜์ˆ™ (๋””์ž์ด๋„ˆ): "์˜์ฒ  ๋‹˜, ์šฐ๋ฆฌ ์„œ๋น„์Šค ๋ธŒ๋žœ๋“œ ์ƒ‰์ƒ์ด #4F46E5 (์ธ๋””๊ณ ) ์ธ๋ฐ, ์ด๊ฑธ Tailwind ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‚˜์š”? ๋งค๋ฒˆ bg-[#4F46E5] ์“ฐ๊ธฐ ๋„ˆ๋ฌด ๋ถˆํŽธํ•ด์š”."
  • ๐Ÿฃ ์˜์ฒ : "์ปค์Šคํ…€ ์ƒ‰์ƒ์ด์š”? ์„ค์ • ํŒŒ์ผ ์–ด๋”˜๊ฐ€์—์„œ..."
  • ๐Ÿฆ ์˜ํ˜ธ (๋ฆฌ๋“œ): "CSS ํŒŒ์ผ์— @theme ๋ธ”๋ก ์ถ”๊ฐ€ํ•˜๋ฉด ๋ผ์š”. ๊ทธ๋Ÿฌ๋ฉด bg-brand-500 ๊ฐ™์€ ํด๋ž˜์Šค๋กœ ์“ธ ์ˆ˜ ์žˆ์–ด์š”."
  • ๐ŸŽจ ์˜์ˆ™: "๊ทธ๋Ÿผ ๋‚˜์ค‘์— ๋ธŒ๋žœ๋“œ ์ƒ‰์ƒ ๋ฐ”๋€Œ์–ด๋„ ํ•œ ๊ณณ๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋˜๊ฒ ๋„ค์š”!"
  • ๐Ÿฆ ์˜ํ˜ธ: "๋ฐ”๋กœ ๊ทธ๊ฒŒ ๋””์ž์ธ ํ† ํฐ์˜ ํ•ต์‹ฌ์ด์—์š”."

๐Ÿค” ์™œ ์•Œ์•„์•ผ ํ•˜๋Š”๊ฐ€

Tailwind ๊ธฐ๋ณธ ํŒ”๋ ˆํŠธ๋Š” ๋ฒ”์šฉ์ ์ด์•ผ. ํ•˜์ง€๋งŒ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—๋Š” ๋ธŒ๋žœ๋“œ ๊ณ ์œ ์˜ ์ƒ‰์ƒ, ํฐํŠธ, ๊ฐ„๊ฒฉ ๊ทœ์น™์ด ์žˆ์–ด.

์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ๊ฐ€ ์„ฑ์žฅํ•˜๋ฉด์„œ:

  • ๋ธŒ๋žœ๋“œ ์ปฌ๋Ÿฌ (#4F46E5) ๋ฅผ 50๊ฐœ ํŒŒ์ผ์— bg-[#4F46E5] ๋กœ ํ•˜๋“œ์ฝ”๋”ฉ
  • ๋‚˜์ค‘์— ๋ธŒ๋žœ๋“œ ์ปฌ๋Ÿฌ๊ฐ€ #7C3AED ๋กœ ๋ณ€๊ฒฝ โ†’ 50๊ฐœ ํŒŒ์ผ ์ˆ˜๋™ ์ˆ˜์ •
  • ํ•˜๋‚˜๋ผ๋„ ๋†“์น˜๋ฉด ํ™”๋ฉด์ด ์–ผ๋ฃฉ๋œ๋ฃฉ

์ด๊ฑธ ๋ฐฉ์ง€ํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ ๋””์ž์ธ ํ† ํฐ + @theme ํ†ตํ•ฉ์ด์•ผ.


๐Ÿ—๏ธ ๋น„์œ ๋กœ ๋จผ์ € ์ดํ•ดํ•˜๊ธฐ

@theme = ์ค‘์•™ ํ†ต์ œ์†Œ

๊ตฐ๋Œ€์˜ ์ค‘์•™ ํ†ต์ œ์†Œ์—์„œ "์˜ค๋Š˜๋ถ€ํ„ฐ ๊ตฐ๋ณต ์ƒ‰๊น”์€ ์นดํ‚ค ๋Œ€์‹  ์˜ฌ๋ฆฌ๋ธŒ์•ผ" ๋ผ๊ณ  ๋ช…๋ นํ•˜๋ฉด ๋ชจ๋“  ๋ถ€๋Œ€๊ฐ€ ๋™์‹œ์— ๋ฐ”๋€Œ์–ด. @theme ์—์„œ --color-brand-500: #4F46E5 ๋ฅผ --color-brand-500: #7C3AED ๋กœ ๋ฐ”๊พธ๋ฉด, bg-brand-500 ์„ ์“ฐ๋Š” ๋ชจ๋“  ๊ณณ์ด ๋™์‹œ์— ๋ณ€๊ฒฝ๋ผ.

๐Ÿ’ก ํ•œ ์ค„๋กœ ๊ธฐ์–ตํ•˜๊ธฐ
@theme ๋Š” Tailwind ๊ฐ€ ์ดํ•ดํ•˜๋Š” CSS ๋ณ€์ˆ˜ ์ €์žฅ์†Œ. ์—ฌ๊ธฐ์„œ ๋ณ€์ˆ˜๋ฅผ ๋ฐ”๊พธ๋ฉด ํ•ด๋‹น ํ† ํฐ์„ ์“ฐ๋Š” ํด๋ž˜์Šค ์ „์ฒด๊ฐ€ ๋ฐ”๋€๋‹ค.


โš™๏ธ @theme ๋””๋ ‰ํ‹ฐ๋ธŒ๋กœ ํ…Œ๋งˆ ์ •์˜

๐ŸŽฏ ์ด ์„น์…˜์„ ์ฝ๊ณ  ๋‚˜๋ฉด:

  • @theme ๊ฐ€ CSS ๋ณ€์ˆ˜(Custom Properties)์™€ ์–ด๋–ป๊ฒŒ ์—ฐ๊ฒฐ๋˜๋Š”์ง€ ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค
  • Tailwind v4 (CSS ๊ธฐ๋ฐ˜) ์™€ v3 (JS ์„ค์ • ํŒŒ์ผ) ๋ฐฉ์‹์˜ ์ฐจ์ด์™€ ์„ ํƒ ๊ธฐ์ค€์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค
  • ์ปค์Šคํ…€ ํ† ํฐ์ด bg-brand-500 ๊ฐ™์€ ํด๋ž˜์Šค๋กœ ์–ด๋–ป๊ฒŒ ๋ณ€ํ™˜๋˜๋Š”์ง€ ๋จธ๋ฆฟ์†์— ๊ทธ๋ฆด ์ˆ˜ ์žˆ๋‹ค

์˜์ˆ™์ด Figma ๋””์ž์ธ ํŒŒ์ผ์„ ๋„˜๊ธฐ๋ฉฐ ์ด๋ ‡๊ฒŒ ๋งํ–ˆ์–ด: "์˜์ฒ  ๋‹˜, ์ด๋ฒˆ ์ฃผ ์ค‘์œผ๋กœ ์šฐ๋ฆฌ ๋ธŒ๋žœ๋“œ ์ƒ‰์ƒ #4F46E5 ๊ฐ€ ๋“ค์–ด๊ฐ„ ๋ฒ„ํŠผ์ด๋ž‘ ๋ฐฐ์ง€ ์ปดํฌ๋„ŒํŠธ ์™„์„ฑํ•ด์ค„ ์ˆ˜ ์žˆ์–ด์š”?"

์˜์ฒ ์ด๊ฐ€ ์ฒ˜์Œ์— ํ•œ ๊ฒƒ: ์ปดํฌ๋„ŒํŠธ๋งˆ๋‹ค bg-[#4F46E5] ๋ฅผ ์ง์ ‘ ํƒ€์ดํ•‘. ๊ทธ๋Ÿฐ๋ฐ ์ดํ‹€ ํ›„ ์˜์ˆ˜ ๋‹˜์ด "๊ฒฝ์Ÿ์‚ฌ ์กฐ์‚ฌ ๊ฒฐ๊ณผ ๋ณด๋ผ์ƒ‰ ๊ณ„์—ด๋กœ ๋ฐ”๊พธ์ž๊ณ  ํ•˜๋„ค์š”. ์ƒ‰์ƒ #7C3AED ๋กœ ์—…๋ฐ์ดํŠธํ•ด์ฃผ์„ธ์š”." ๋ผ๊ณ  ์Šฌ๋ž™์„ ๋‚ ๋ ธ์–ด.

์˜์ฒ ์ด: "...34๊ฐœ ํŒŒ์ผ์—์„œ #4F46E5 ๋ฅผ ์ฐพ์•„์„œ ๋ฐ”๊ฟ”์•ผ ํ•œ๋‹ค๊ณ ์š”?"

๐Ÿฆ ์˜ํ˜ธ: "๊ทธ๋ž˜์„œ ๋””์ž์ธ ํ† ํฐ์„ @theme ์— ํ•œ ๊ณณ์— ๋ชจ์•„์•ผ ํ•˜๋Š” ๊ฑฐ์˜ˆ์š”. @theme ๋Š” Tailwind ๊ฐ€ CSS ๋ณ€์ˆ˜๋ฅผ ํด๋ž˜์Šค๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ๋Š” ์ค‘์•™ ์ฐฝ๊ณ  ์—์š”. ์ฐฝ๊ณ ์—์„œ ๋ฐ”๊พธ๋ฉด ์ „์ฒด๊ฐ€ ๋ฐ”๋€Œ์–ด์š”."


Tailwind v4 ๋ฐฉ์‹ (CSS ๊ธฐ๋ฐ˜ โ€” ๊ถŒ์žฅ)

Tailwind v4 ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์„ค์ • ํŒŒ์ผ ์—†์ด, CSS ํŒŒ์ผ ์•ˆ์˜ @theme ๋ธ”๋ก์—์„œ ๋ชจ๋“  ํ…Œ๋งˆ๋ฅผ ์ •์˜ํ•ด. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ดํ•ดํ•˜๋Š” CSS ๋ณ€์ˆ˜๋ฅผ ์ง์ ‘ ์จ์„œ ๋Ÿฐํƒ€์ž„์—๋„ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒŒ ์žฅ์ ์ด์•ผ.

/* app/globals.css */
@import "tailwindcss";
 
/* ๐Ÿฆ ์˜ํ˜ธ: "@theme ์•ˆ์˜ ๋ณ€์ˆ˜๋“ค์ด bg-brand-500, font-sans ๊ฐ™์€ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค๋กœ ์ž๋™ ๋ณ€ํ™˜๋ผ์š”. */
/*           ๋„ค์ด๋ฐ ๊ทœ์น™์€ --{์นดํ…Œ๊ณ ๋ฆฌ}-{์ด๋ฆ„}: ๊ฐ’ ํ˜•ํƒœ์˜ˆ์š”." */
@theme {
  /* ์ƒ‰์ƒ ํ† ํฐ: --color-{์ด๋ฆ„} โ†’ bg-{์ด๋ฆ„}, text-{์ด๋ฆ„}, border-{์ด๋ฆ„} ํด๋ž˜์Šค ์ƒ์„ฑ */
  --color-brand-50:  oklch(0.97 0.02 270);  /* ๊ฐ€์žฅ ๋ฐ์€ ์ƒ‰ */
  --color-brand-100: oklch(0.93 0.05 270);
  --color-brand-200: oklch(0.86 0.10 270);
  --color-brand-300: oklch(0.78 0.15 270);
  --color-brand-400: oklch(0.68 0.20 270);
  --color-brand-500: oklch(0.58 0.24 270);  /* ๐ŸŽจ ์˜์ˆ™์ด ์š”์ฒญํ•œ ๋ฉ”์ธ ๋ธŒ๋žœ๋“œ ์ƒ‰ */
  --color-brand-600: oklch(0.50 0.22 270);  /* hover ์‹œ ์‚ฌ์šฉ */
  --color-brand-700: oklch(0.42 0.20 270);
  --color-brand-800: oklch(0.34 0.17 270);
  --color-brand-900: oklch(0.27 0.13 270);  /* ๊ฐ€์žฅ ์–ด๋‘์šด ์ƒ‰ */
 
  /* ํฐํŠธ ํ† ํฐ: --font-{์ด๋ฆ„} โ†’ font-{์ด๋ฆ„} ํด๋ž˜์Šค ์ƒ์„ฑ */
  --font-sans: 'Pretendard', 'Noto Sans KR', sans-serif;
  --font-display: 'Noto Serif KR', Georgia, serif;
 
  /* ์ปค์Šคํ…€ breakpoint: --breakpoint-{์ด๋ฆ„} โ†’ {์ด๋ฆ„}: ๋ฐ˜์‘ํ˜• prefix ์ƒ์„ฑ */
  --breakpoint-xs: 480px;   /* xs:flex ์ฒ˜๋Ÿผ ์‚ฌ์šฉ ๊ฐ€๋Šฅ */
  --breakpoint-3xl: 1920px; /* ์ดˆ๋Œ€ํ˜• ๋ชจ๋‹ˆํ„ฐ ๋Œ€์‘ */
 
  /* ์ปค์Šคํ…€ spacing: --spacing-{์ด๋ฆ„} โ†’ pt-{์ด๋ฆ„}, mt-{์ด๋ฆ„} ๋“ฑ ์ƒ์„ฑ */
  --spacing-18: 4.5rem;    /* 72px โ€” 8์˜ ๋ฐฐ์ˆ˜๊ฐ€ ์•„๋‹Œ ์ปค์Šคํ…€ ๊ฐ’ */
  --spacing-22: 5.5rem;    /* 88px */
}

์ด์ œ @theme ์— ์ •์˜ํ•œ ํ† ํฐ๋“ค์ด Tailwind ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค๋กœ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ด:

<!-- bg-brand-500, text-brand-600 ์ด์ œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ! -->
<div class="bg-brand-500 text-white hover:bg-brand-600">๋ธŒ๋žœ๋“œ ๋ฒ„ํŠผ</div>
<p class="font-display text-2xl">๋ธŒ๋žœ๋“œ ํฐํŠธ ์ œ๋ชฉ</p>
<div class="pt-18">์ปค์Šคํ…€ ๊ฐ„๊ฒฉ 72px</div>
<div class="xs:flex hidden">480px ์ด์ƒ์—์„œ๋งŒ flex</div>

๋‚˜์ค‘์— ๋ธŒ๋žœ๋“œ ์ปฌ๋Ÿฌ๊ฐ€ ๋ฐ”๋€Œ์–ด๋„? @theme ์˜ --color-brand-500 ํ•œ ์ค„๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ํ”„๋กœ์ ํŠธ ์ „์ฒด์— ๋ฐ˜์˜๋ผ.


Tailwind v3 ๋ฐฉ์‹ (tailwind.config.js)

Next.js ํ”„๋กœ์ ํŠธ๊ฐ€ ์•„์ง v3 ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด JS ์„ค์ • ํŒŒ์ผ์—์„œ ํ…Œ๋งˆ๋ฅผ ํ™•์žฅํ•ด. extend ํ‚ค๋ฅผ ํ†ตํ•ด ๊ธฐ์กด ํŒ”๋ ˆํŠธ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ์ปค์Šคํ…€ ํ† ํฐ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์ด์•ผ.

๐Ÿฆ ์˜ํ˜ธ: "์ค‘์š”ํ•œ ํฌ์ธํŠธ๊ฐ€ ์žˆ์–ด์š”. theme.extend ์— ๋„ฃ์œผ๋ฉด ๊ธฐ์กด Tailwind ์ƒ‰์ƒ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ์ถ”๊ฐ€๋ผ์š”. ํ•˜์ง€๋งŒ theme ์— ๋ฐ”๋กœ colors ๋ฅผ ๋„ฃ์œผ๋ฉด ๊ธฐ์กด ํŒ”๋ ˆํŠธ๊ฐ€ ์ „๋ถ€ ๋‚ ์•„๊ฐ€์š”. extend ๋ฅผ ๋นผ๋จน์œผ๋ฉด text-gray-500 ๊ฐ™์€ ๊ธฐ๋ณธ ํด๋ž˜์Šค๋„ ์—†์–ด์ ธ์š”."

// tailwind.config.js
const { fontFamily } = require('tailwindcss/defaultTheme');
 
module.exports = {
  theme: {
    extend: {
      // โœ… extend ์•ˆ์— ๋„ฃ์–ด์•ผ ๊ธฐ์กด ํŒ”๋ ˆํŠธ ์œ ์ง€!
      colors: {
        brand: {
          50:  '#eef2ff',
          100: '#e0e7ff',
          200: '#c7d2fe',
          300: '#a5b4fc',
          400: '#818cf8',
          500: '#6366f1',  // ๋ฉ”์ธ ๋ธŒ๋žœ๋“œ ์ƒ‰
          600: '#4f46e5',
          700: '#4338ca',
          800: '#3730a3',
          900: '#312e81',
          950: '#1e1b4b',
        },
      },
      fontFamily: {
        // ๊ธฐ์กด sans ํฐํŠธ ์Šคํƒ ์•ž์— Pretendard ์ถ”๊ฐ€ (fallback ์œ ์ง€)
        sans: ['Pretendard', ...fontFamily.sans],
        display: ['Noto Serif KR', 'Georgia', 'serif'],
      },
      screens: {
        xs: '480px',     // ์ถ”๊ฐ€ breakpoint
        '3xl': '1920px', // ์ดˆ๋Œ€ํ˜• ํ™”๋ฉด
      },
    },
  },
};
ํ•ญ๋ชฉv4 (@theme in CSS)v3 (tailwind.config.js)
์„ค์ • ์œ„์น˜CSS ํŒŒ์ผ ์•ˆJS ์„ค์ • ํŒŒ์ผ
๋Ÿฐํƒ€์ž„ ์ ‘๊ทผโœ… CSS ๋ณ€์ˆ˜๋กœ JS์—์„œ๋„ ์ ‘๊ทผ ๊ฐ€๋ŠฅโŒ ๋นŒ๋“œ ํƒ€์ž„์—๋งŒ ํด๋ž˜์Šค ์ƒ์„ฑ
์ƒ‰์ƒ ํฌ๋งทoklch, hsl, rgb ๋ชจ๋‘์ฃผ๋กœ hex, hsl
๊ถŒ์žฅโœ… ์‹ ๊ทœ ํ”„๋กœ์ ํŠธ๊ธฐ์กด v3 ํ”„๋กœ์ ํŠธ ์œ ์ง€ ๋ณด์ˆ˜

๐ŸŽจ ์ปค์Šคํ…€ ์ƒ‰์ƒ ์ถ”๊ฐ€

๋ธŒ๋žœ๋“œ ์ปฌ๋Ÿฌ ์ „์ฒด ์Šค์ผ€์ผ ์ถ”๊ฐ€

/* globals.css โ€” @theme ๋ฐฉ์‹ */
@theme {
  /* oklch: ์ตœ์‹  ์ƒ‰์ƒ ํ˜•์‹, ๋” ์ •ํ™•ํ•œ ์ƒ‰์ƒ ํ‘œํ˜„ */
  --color-brand-50:  #f5f3ff;
  --color-brand-100: #ede9fe;
  --color-brand-200: #ddd6fe;
  --color-brand-300: #c4b5fd;
  --color-brand-400: #a78bfa;
  --color-brand-500: #8b5cf6;
  --color-brand-600: #7c3aed;
  --color-brand-700: #6d28d9;
  --color-brand-800: #5b21b6;
  --color-brand-900: #4c1d95;
  --color-brand-950: #2e1065;
 
  /* ์‹œ๋งจํ‹ฑ ์ƒ‰์ƒ (์—ญํ•  ๊ธฐ๋ฐ˜ ์ด๋ฆ„) */
  --color-success-500: #22c55e;
  --color-warning-500: #f59e0b;
  --color-danger-500:  #ef4444;
  --color-info-500:    #3b82f6;
}
// ์‚ฌ์šฉ ์˜ˆ
function AlertBanner({ type, message }: Props) {
  const styles = {
    success: 'bg-success-50 border-success-200 text-success-700',
    warning: 'bg-warning-50 border-warning-200 text-warning-700',
    danger:  'bg-danger-50  border-danger-200  text-danger-700',
    info:    'bg-info-50    border-info-200    text-info-700',
  };
 
  return (
    <div className={`rounded-lg border p-4 ${styles[type]}`}>
      {message}
    </div>
  );
}

โœ๏ธ ์ปค์Šคํ…€ ํฐํŠธ ์ถ”๊ฐ€

ํ•œ๊ตญ์–ด ํฐํŠธ (Pretendard) ์ ์šฉ

/* globals.css */
 
/* 1. ํฐํŠธ import (Google Fonts ๋˜๋Š” CDN) */
@import url('https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/variable/pretendardvariable.css');
 
@import "tailwindcss";
 
@theme {
  /* 2. @theme ์— ํฐํŠธ ๋“ฑ๋ก */
  --font-sans: 'Pretendard Variable', 'Pretendard', -apple-system,
               BlinkMacSystemFont, system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
}
// 3. body ์— ๊ธฐ๋ณธ ํฐํŠธ ์ ์šฉ
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="ko">
      {/* font-sans: --font-sans ์— ๋“ฑ๋กํ•œ Pretendard ๊ฐ€ ์ ์šฉ๋จ */}
      <body className="font-sans antialiased">
        {children}
      </body>
    </html>
  );
}

Next.js next/font ์™€ ํ†ตํ•ฉ (๊ถŒ์žฅ)

// app/layout.tsx
import { Inter, Noto_Sans_KR } from 'next/font/google';
 
const inter = Inter({
  subsets: ['latin'],
  variable: '--font-inter',
});
 
const notoSansKr = Noto_Sans_KR({
  subsets: ['latin'],
  weight: ['400', '500', '700'],
  variable: '--font-noto-sans-kr',
});
 
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="ko" className={`${inter.variable} ${notoSansKr.variable}`}>
      <body className="font-sans">
        {children}
      </body>
    </html>
  );
}
/* globals.css */
@theme {
  --font-sans: var(--font-noto-sans-kr), var(--font-inter), sans-serif;
}

๐Ÿ“ ์ปค์Šคํ…€ Breakpoint ์ถ”๊ฐ€

@theme {
  /* ์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ์˜ ์ปค์Šคํ…€ breakpoint */
  --breakpoint-xs: 30rem;     /* 480px โ€” ํฐ ์Šค๋งˆํŠธํฐ */
  --breakpoint-3xl: 120rem;   /* 1920px โ€” 4K ๋ชจ๋‹ˆํ„ฐ */
 
  /* ๊ธฐ์กด breakpoint ์žฌ์ •์˜ (์‹ ์ค‘ํžˆ!) */
  /* --breakpoint-md: 48rem; */  /* ๊ธฐ๋ณธ 768px ์œ ์ง€ */
}
<!-- ์ปค์Šคํ…€ breakpoint ์‚ฌ์šฉ -->
<div class="grid grid-cols-1 xs:grid-cols-2 md:grid-cols-3 3xl:grid-cols-4">

๐Ÿ’ป ์‹ค์ „: ์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ ๋””์ž์ธ ์‹œ์Šคํ…œ ๊ตฌ์ถ•

/* app/globals.css โ€” ์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ ์ „์ฒด ๋””์ž์ธ ์‹œ์Šคํ…œ */
@import "tailwindcss";
 
@theme {
  /* ===== ๋ธŒ๋žœ๋“œ ์ƒ‰์ƒ ===== */
  --color-brand-50:  #f5f3ff;
  --color-brand-100: #ede9fe;
  --color-brand-200: #ddd6fe;
  --color-brand-300: #c4b5fd;
  --color-brand-400: #a78bfa;
  --color-brand-500: #8b5cf6;
  --color-brand-600: #7c3aed;  /* ์ฃผ์š” ๋ฒ„ํŠผ, ๋งํฌ */
  --color-brand-700: #6d28d9;
  --color-brand-800: #5b21b6;
  --color-brand-900: #4c1d95;
 
  /* ===== ์‹œ๋งจํ‹ฑ ์ƒ‰์ƒ ===== */
  --color-success: #16a34a;
  --color-warning: #d97706;
  --color-danger:  #dc2626;
  --color-info:    #2563eb;
 
  /* ===== ํฐํŠธ ===== */
  --font-sans: 'Pretendard Variable', -apple-system, sans-serif;
 
  /* ===== ์ปค์Šคํ…€ Breakpoint ===== */
  --breakpoint-xs: 30rem;
 
  /* ===== ์ปค์Šคํ…€ Spacing ===== */
  --spacing-18: 4.5rem;
 
  /* ===== ์ปค์Šคํ…€ Border Radius ===== */
  --radius-2xl: 1rem;
  --radius-3xl: 1.5rem;
 
  /* ===== ์ปค์Šคํ…€ Box Shadow ===== */
  --shadow-card: 0 2px 8px -2px rgb(0 0 0 / 0.1), 0 4px 12px -4px rgb(0 0 0 / 0.1);
}
// ๋””์ž์ธ ํ† ํฐ ๊ธฐ๋ฐ˜ ๋ฒ„ํŠผ ์ปดํฌ๋„ŒํŠธ
type ButtonVariant = 'primary' | 'secondary' | 'danger';
 
const variantClass: Record<ButtonVariant, string> = {
  primary:   'bg-brand-600 text-white hover:bg-brand-700 focus-visible:ring-brand-500',
  secondary: 'bg-brand-50 text-brand-700 hover:bg-brand-100 focus-visible:ring-brand-300',
  danger:    'bg-red-600 text-white hover:bg-red-700 focus-visible:ring-red-500',
};
 
function Button({ variant = 'primary', children, ...props }: Props) {
  return (
    <button
      className={`
        rounded-xl px-6 py-3 font-semibold text-sm
        transition-all duration-200 ease-out
        focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2
        active:scale-95
        disabled:cursor-not-allowed disabled:opacity-50
        ${variantClass[variant]}
      `}
      {...props}
    >
      {children}
    </button>
  );
}

๐Ÿ ์ด๋ฒˆ์— ๋ฐฐ์šด ๋‚ด์šฉ ์ด์ •๋ฆฌ

๊ฐœ๋…๋ฐฉ๋ฒ•๊ฒฐ๊ณผ
์ปค์Šคํ…€ ์ƒ‰์ƒ@theme { --color-brand-500: ... }bg-brand-500 ์‚ฌ์šฉ ๊ฐ€๋Šฅ
์ปค์Šคํ…€ ํฐํŠธ@theme { --font-sans: ... }font-sans ์— ์ ์šฉ
์ปค์Šคํ…€ Breakpoint@theme { --breakpoint-xs: 30rem }xs: ์ ‘๋‘์‚ฌ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
์‹œ๋งจํ‹ฑ ์ƒ‰์ƒ--color-success, --color-danger์—ญํ•  ๊ธฐ๋ฐ˜ ์ด๋ฆ„
๋””์ž์ธ ํ† ํฐ@theme ํ•œ ๊ณณ์—์„œ ๊ด€๋ฆฌ์ „์—ญ ๋ณ€๊ฒฝ ์šฉ์ด

๐Ÿ“ ๋งˆ๋ฌด๋ฆฌ ํ€ด์ฆˆ

Q1. ์˜์ˆ™์ด ๋ธŒ๋žœ๋“œ ์ƒ‰์ƒ์„ #8B5CF6 ์œผ๋กœ ์ •ํ–ˆ๋‹ค. ์ด๋ฅผ Tailwind ์—์„œ bg-brand-500, text-brand-600 ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์–ด๋””์— ๋ฌด์—‡์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š”๊ฐ€?

โœ… ์ •๋‹ต: CSS ํŒŒ์ผ์˜ @theme ๋ธ”๋ก์— --color-brand-500: #8b5cf6; ๊ณผ ์ „์ฒด ์Šค์ผ€์ผ(50~950)์„ ์ •์˜ํ•œ๋‹ค.

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค:

  • @theme ์—์„œ --color-{name}-{scale}: ํ˜•์‹์œผ๋กœ ์ •์˜ํ•˜๋ฉด Tailwind ๊ฐ€ ์ž๋™์œผ๋กœ bg-{name}-{scale}, text-{name}-{scale}, border-{name}-{scale} ๋“ฑ ๋ชจ๋“  ์ƒ‰์ƒ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ์ƒ์„ฑํ•ด.
  • ๋‹จ ํ•˜๋‚˜์˜ ๊ฐ’(500)๋งŒ ์ถ”๊ฐ€ํ•ด๋„ ์‚ฌ์šฉ์€ ๋˜์ง€๋งŒ, ๋ณดํ†ต ์ „์ฒด ์Šค์ผ€์ผ์„ ์ •์˜ํ•ด์•ผ ๋ฐ์Œ/์–ด๋‘์›€ ๋ณ€ํ˜•์„ ์ž์œ ๋กญ๊ฒŒ ์“ธ ์ˆ˜ ์žˆ์–ด.
  • ๐Ÿ“Œ ํ•ต์‹ฌ ๊ธฐ์–ต๋ฒ•: "@theme { --color-name-scale: value; } โ†’ Tailwind ๊ฐ€ ๋‚˜๋จธ์ง€ ํด๋ž˜์Šค๋ฅผ ์ž๋™ ์ƒ์„ฑ."

Q2. tailwind.config.js ์—์„œ theme.colors ์™€ theme.extend.colors ์˜ ์ฐจ์ด๋Š”?

โœ… ์ •๋‹ต: theme.colors ๋Š” ๊ธฐ์กด Tailwind ์ƒ‰์ƒ ํŒ”๋ ˆํŠธ ์ „์ฒด๋ฅผ ๊ต์ฒดํ•˜๊ณ , theme.extend.colors ๋Š” ๊ธฐ์กด ํŒ”๋ ˆํŠธ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ์ƒˆ ์ƒ‰์ƒ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค:

  • theme.colors: { brand: {...} } ๋ฅผ ์„ค์ •ํ•˜๋ฉด ๊ธฐ์กด์˜ blue, gray, red ๋“ฑ ๋ชจ๋“  ๋‚ด์žฅ ์ƒ‰์ƒ์ด ์‚ฌ๋ผ์ง€๊ณ  brand ๋งŒ ๋‚จ์•„.
  • theme.extend.colors: { brand: {...} } ๋Š” ๊ธฐ์กด ์ƒ‰์ƒ์€ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๋ฉด์„œ brand ์ƒ‰์ƒ์„ ์ถ”๊ฐ€ํ•ด. ์‹ค๋ฌด์—์„œ๋Š” ๊ฑฐ์˜ ํ•ญ์ƒ extend ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ด.
  • ๐Ÿ“Œ ํ•ต์‹ฌ ๊ธฐ์–ต๋ฒ•: "๊ต์ฒด = theme.colors, ์ถ”๊ฐ€ = theme.extend.colors. ์‹ค๋ฌด๋Š” ํ•ญ์ƒ extend."

Q3. ์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ๊ฐ€ ์„ฑ์žฅํ•ด์„œ 480px (xs) breakpoint ๊ฐ€ ํ•„์š”ํ•ด์กŒ๋‹ค. Tailwind v4 ์—์„œ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

โœ… ์ •๋‹ต: globals.css ์˜ @theme ๋ธ”๋ก์— --breakpoint-xs: 30rem; ์„ ์ถ”๊ฐ€ํ•œ๋‹ค. (480px รท 16 = 30rem)

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค:

  • Tailwind v4 ์—์„œ breakpoint ๋Š” --breakpoint-{name}: {value} ํ˜•์‹์œผ๋กœ @theme ์— ์ถ”๊ฐ€ํ•ด.
  • 30rem = 480px (1rem = 16px ๊ธฐ์ค€).
  • ์ถ”๊ฐ€ ํ›„ xs:grid-cols-2 ์ฒ˜๋Ÿผ xs: ์ ‘๋‘์‚ฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด.
  • Tailwind v3 ์—์„œ๋Š” tailwind.config.js ์˜ theme.extend.screens: { xs: '480px' } ๋กœ ์ถ”๊ฐ€ํ•ด.
  • ๐Ÿ“Œ ํ•ต์‹ฌ ๊ธฐ์–ต๋ฒ•: "v4 = @theme CSS, v3 = tailwind.config.js. ๋‹จ์œ„๋Š” rem(16 ๋‚˜๋ˆ„๊ธฐ)."

๐Ÿฃ ์˜์ฒ ์ด์˜ ํ‡ด๊ทผ ์ผ๊ธฐ

์˜ค๋Š˜ @theme ๋ธ”๋ก ํ•˜๋‚˜๋กœ ์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ ์ „์ฒด ๋””์ž์ธ ์‹œ์Šคํ…œ ๊ธฐ์ดˆ๋ฅผ ์žก์•˜๋‹ค. ์˜์ˆ™ ๋‹˜์ด ํ”ผ๊ทธ๋งˆ์—์„œ ๋ธŒ๋žœ๋“œ ์ƒ‰์ƒ ํŒ”๋ ˆํŠธ ๋ฝ‘์•„์คฌ๊ณ , ๊ทธ๊ฑธ CSS ๋ณ€์ˆ˜๋กœ ๋“ฑ๋กํ–ˆ๋”๋‹ˆ bg-brand-600 ๊ฐ™์€ ํด๋ž˜์Šค๊ฐ€ ์ƒ๊ฒจ๋‚ฌ๋‹ค.

์˜ํ˜ธ ๋‹˜์ด "๋””์ž์ธ ํ† ํฐ์€ ๋””์ž์ด๋„ˆ์™€ ๊ฐœ๋ฐœ์ž ์‚ฌ์ด์˜ ๊ณตํ†ต ์–ธ์–ด์˜ˆ์š”. brand-600 ์ด๋ผ๊ณ  ํ•˜๋ฉด ๋‘˜ ๋‹ค ๊ฐ™์€ ์ƒ‰์„ ๋– ์˜ฌ๋ ค์•ผ ํ•ด์š”" ๋ผ๊ณ  ํ•˜์…จ๋Š”๋ฐ, ๊ทธ๊ฒŒ ์ •๋ง ๋งž๋Š” ๋ง ๊ฐ™๋‹ค.

๐Ÿ’ก ์˜ค๋Š˜์˜ ๊ตํ›ˆ: "๋””์ž์ธ ํ† ํฐ ํ•˜๋‚˜๋ฅผ ์ž˜ ์ •์˜ํ•˜๋ฉด, ๊ทธ๊ฑธ ์ฐธ์กฐํ•˜๋Š” ์ˆ˜๋ฐฑ ์ค„์˜ ์ฝ”๋“œ๊ฐ€ ํ•œ ๋ฒˆ์— ๋ฐ”๋€๋‹ค. ์ด๊ฒŒ ์œ ์ง€๋ณด์ˆ˜์˜ ๋ณธ์งˆ์ด๋‹ค."

์˜ค๋Š˜ ์ผ ๋งˆ์น˜๊ณ  ์˜ํ˜ธ ๋‹˜์ด๋ž‘ ํŽธ์˜์  ๋งฅ์ฃผ ํ•œ ์ž” ํ–ˆ๋‹ค. ๊ฐ€๋” ์ด๋ ‡๊ฒŒ ํŽธํ•˜๊ฒŒ ์–˜๊ธฐํ•˜๋ฉด์„œ ๋ฐฐ์šฐ๋Š” ๊ฒŒ ๊ณต์‹ ๋ฌธ์„œ๋ณด๋‹ค ๋” ๋งŽ์ด ๋‚จ๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ์ข‹์€ ํŒ€ ๋งŒ๋‚ฌ๋‹ค๋Š” ์ƒ๊ฐ์ด ์ƒˆ์‚ผ ๋“ ๋‹ค. ๐Ÿบ


๐Ÿ”— ๋” ์•Œ์•„๋ณด๊ธฐ