--- id: frontend-design-tokens title: Design Tokens — 색 / spacing / type / 토큰화 category: Coding status: draft source_trust_level: B verification_status: conceptual created_at: 2026-05-09 updated_at: 2026-05-09 tags: [frontend, design-tokens, design-system, vibe-coding] tech_stack: { language: "TS / CSS / Figma", applicable_to: ["Web", "iOS", "Android"] } applied_in: [] aliases: [design tokens, tokens.json, Style Dictionary, Figma Variables] --- # Design Tokens > 색 / 크기 / 타이포 = 단일 source. **Figma Variables → tokens.json → 각 platform** (CSS / iOS / Android) 자동 변환. Style Dictionary / Tokens Studio. ## 📖 핵심 개념 - Token: 디자인 결정 단위 (`color.brand.500 = #3b82f6`). - Layer: primitive (raw) → semantic (intent) → component. - Alias: `bg-surface` → `gray-50` → `#fafafa`. - Theme: dark / light 가 같은 semantic 의 다른 primitive 매핑. ## 💻 코드 패턴 ### tokens.json (W3C Design Tokens) ```json { "color": { "blue": { "500": { "$value": "#3b82f6", "$type": "color" }, "600": { "$value": "#2563eb", "$type": "color" } }, "brand": { "primary": { "$value": "{color.blue.500}", "$type": "color" } } }, "spacing": { "1": { "$value": "4px", "$type": "dimension" }, "2": { "$value": "8px", "$type": "dimension" } } } ``` ### Style Dictionary 빌드 ```ts // build.ts import StyleDictionary from 'style-dictionary'; StyleDictionary.extend({ source: ['tokens/**/*.json'], platforms: { css: { transformGroup: 'css', buildPath: 'src/styles/', files: [{ destination: 'tokens.css', format: 'css/variables' }], }, ios: { transformGroup: 'ios-swift', buildPath: 'ios/Tokens/', files: [{ destination: 'Tokens.swift', format: 'ios-swift/class.swift' }], }, android: { transformGroup: 'android', buildPath: 'android/app/src/main/res/values/', files: [ { destination: 'colors.xml', format: 'android/colors' }, { destination: 'dimens.xml', format: 'android/dimens' }, ], }, }, }).buildAllPlatforms(); ``` ### CSS 결과 ```css :root { --color-blue-500: #3b82f6; --color-brand-primary: var(--color-blue-500); --spacing-1: 4px; } ``` ### iOS Swift ```swift public class Tokens { public static let colorBlue500 = UIColor(red: 0.231, green: 0.510, blue: 0.965, alpha: 1) public static let colorBrandPrimary = colorBlue500 public static let spacing1: CGFloat = 4 } ``` ### Android XML ```xml #3b82f6 4dp ``` ### Layer 패턴 ```json // primitive "color.blue.500": "#3b82f6", "color.gray.50": "#fafafa", // semantic (intent) "color.bg.surface": "{color.gray.50}", "color.text.brand": "{color.blue.500}", // component "button.primary.bg": "{color.text.brand}" ``` ### Theme switching ```json // light.json "color.bg.surface": "{color.gray.50}", // dark.json "color.bg.surface": "{color.gray.900}" ``` ```css :root { --color-bg-surface: var(--gray-50); } .dark { --color-bg-surface: var(--gray-900); } ``` ### Figma Tokens Studio - Figma plugin: 디자이너가 토큰 편집. - GitHub sync: 디자이너 변경 → PR. - Style Dictionary 가 PR 의 토큰을 빌드. ## 🤔 의사결정 기준 | 규모 | 도구 | |---|---| | 1 platform 작은 앱 | Tailwind theme 으로 충분 | | Web 만 강력 | CSS variables + tokens.json | | Cross-platform (web/iOS/AOS) | Style Dictionary | | 디자이너 직접 편집 | Figma Variables + Tokens Studio | | Figma 없음 | tokens.json 직접 + PR review | ## ❌ 안티패턴 - **Magic value 코드 깊이**: hex 직접 작성. 토큰화. - **Primitive 만 — semantic 없음**: rebrand 시 모든 코드 변경. - **너무 많은 token (10000+)**: 너무 잘게. 적당히 추상. - **Component token 만 — primitive 안 보임**: 새 컴포넌트 만들 때 base 없음. - **Cross-platform 없이 platform 별 다른 색**: brand 일관성 깨짐. - **No naming convention**: 같은 의미 다른 이름. ## 🤖 LLM 활용 힌트 - 3 layer (primitive → semantic → component). - Style Dictionary cross-platform 빌드. - Figma → tokens.json sync. ## 🔗 관련 문서 - [[Frontend_Tailwind_Architecture]]