브랜드 컬러 팔레트 확장: 디자인 시스템을 위한 색상 토큰 설계

UX 디자인

컬러 팔레트디자인 토큰브랜드 색상다크 모드색상 시스템

이 글은 누구를 위한 것인가

  • 브랜드 컬러 하나를 받아서 디자인 시스템 전체 팔레트를 만들어야 하는 디자이너
  • 라이트/다크 모드 색상 토큰을 어떻게 설계해야 할지 모르는 팀
  • Figma 변수와 CSS 변수를 연결하려는 개발자·디자이너

들어가며

브랜드 컬러가 #FF4B2B 하나 있다고 디자인 시스템이 완성되지 않는다. Primary 500부터 50까지의 스케일, 다크 모드 대응, 시맨틱 토큰(배경·텍스트·테두리)으로 확장해야 한다.

이 글은 bluefoxdev.kr의 디자인 시스템 색상 설계 를 참고하여 작성했습니다.


1. HSL 기반 색상 스케일 생성

[Primary 컬러 스케일 생성 방법]

브랜드 컬러: #FF4B2B (HSL: 11, 100%, 58%)

스케일 생성 규칙:
  50:  H=11, S=100%, L=96% (가장 밝음)
  100: H=11, S=100%, L=90%
  200: H=11, S=100%, L=80%
  300: H=11, S=100%, L=70%
  400: H=11, S=100%, L=64%
  500: H=11, S=100%, L=58% ← 브랜드 컬러
  600: H=11, S=100%, L=48%
  700: H=11, S=100%, L=38%
  800: H=11, S=100%, L=28%
  900: H=11, S=100%, L=18%
  950: H=11, S=100%, L=10% (가장 어두움)

[Gray 스케일 (중성색)]
  브랜드 색상에 살짝 Hue를 가미 (따뜻한 브랜드 → 따뜻한 회색)
  50:  H=20, S=10%, L=98%
  100: H=20, S=10%, L=95%
  ...
  900: H=20, S=10%, L=10%

2. 시맨틱 토큰 설계

/* Design Tokens: Semantic Layer */
:root {
  /* Primary Scale */
  --color-primary-50: hsl(11, 100%, 96%);
  --color-primary-100: hsl(11, 100%, 90%);
  --color-primary-500: hsl(11, 100%, 58%);  /* 브랜드 컬러 */
  --color-primary-600: hsl(11, 100%, 48%);
  --color-primary-700: hsl(11, 100%, 38%);
  
  /* Semantic Colors - Light Mode */
  --color-background-default: #ffffff;
  --color-background-subtle: var(--color-gray-50);
  --color-background-muted: var(--color-gray-100);
  
  --color-text-default: var(--color-gray-900);
  --color-text-secondary: var(--color-gray-600);
  --color-text-disabled: var(--color-gray-400);
  
  --color-border-default: var(--color-gray-200);
  --color-border-strong: var(--color-gray-400);
  
  --color-interactive-primary: var(--color-primary-500);
  --color-interactive-primary-hover: var(--color-primary-600);
  --color-interactive-primary-active: var(--color-primary-700);
  
  /* Status Colors */
  --color-success-subtle: hsl(142, 76%, 95%);
  --color-success-default: hsl(142, 76%, 36%);
  --color-danger-subtle: hsl(0, 86%, 97%);
  --color-danger-default: hsl(0, 86%, 56%);
  --color-warning-subtle: hsl(38, 100%, 95%);
  --color-warning-default: hsl(38, 100%, 50%);
}

/* Dark Mode Override */
[data-theme="dark"] {
  --color-background-default: hsl(20, 10%, 8%);
  --color-background-subtle: hsl(20, 10%, 12%);
  --color-background-muted: hsl(20, 10%, 16%);
  
  --color-text-default: hsl(20, 10%, 95%);
  --color-text-secondary: hsl(20, 10%, 70%);
  --color-text-disabled: hsl(20, 10%, 45%);
  
  --color-border-default: hsl(20, 10%, 22%);
  
  /* Primary는 다크모드에서 밝게 조정 */
  --color-interactive-primary: var(--color-primary-400);
  --color-interactive-primary-hover: var(--color-primary-300);
}

3. Figma 변수와 CSS 변수 매핑

// Design Token을 JSON으로 내보내기 (Style Dictionary 형식)
const colorTokens = {
  color: {
    background: {
      default: { value: "{color.white}", type: "color" },
      subtle: { value: "{color.gray.50}", type: "color" },
    },
    text: {
      default: { value: "{color.gray.900}", type: "color" },
      secondary: { value: "{color.gray.600}", type: "color" },
    },
    interactive: {
      primary: { value: "{color.primary.500}", type: "color" },
      primaryHover: { value: "{color.primary.600}", type: "color" },
    },
  },
};

// Style Dictionary 설정
// 위 JSON → CSS 변수, iOS 색상, Android 색상 자동 생성
const StyleDictionary = require("style-dictionary");
StyleDictionary.extend({
  source: ["tokens/**/*.json"],
  platforms: {
    css: {
      transformGroup: "css",
      files: [{
        destination: "variables.css",
        format: "css/variables",
      }],
    },
  },
}).buildAllPlatforms();

마무리

색상 토큰 설계의 핵심은 레이어다: 원시 값(Primary-500) → 시맨틱 토큰(interactive.primary) → 컴포넌트 토큰(button.background). 컴포넌트가 원시 값을 직접 쓰면 테마 변경 시 모든 컴포넌트를 수정해야 한다. 시맨틱 토큰을 중간에 두면 다크 모드 전환이 토큰 값만 바꾸는 것으로 해결된다.