본문 바로가기
Frontend2024년 11월 17일7분 읽기

CSS 변수(Custom Properties) 실전 디자인 시스템

YS
김영삼
조회 746

CSS Custom Properties 기초

CSS Custom Properties(CSS 변수)는 -- 접두사로 선언하고 var() 함수로 참조합니다. JavaScript에서 런타임에 변경할 수 있어, Sass 변수와 달리 동적 테마 전환이 가능합니다.

디자인 토큰 정의

:root {
  /* 색상 토큰 */
  --color-primary-50: #eff6ff;
  --color-primary-100: #dbeafe;
  --color-primary-500: #3b82f6;
  --color-primary-600: #2563eb;
  --color-primary-700: #1d4ed8;
  --color-primary-900: #1e3a5f;

  /* 시맨틱 색상 */
  --color-bg: #ffffff;
  --color-text: #1a1a2e;
  --color-text-muted: #6b7280;
  --color-border: #e5e7eb;
  --color-surface: #f9fafb;

  /* 타이포그래피 */
  --font-sans: 'Pretendard', -apple-system, sans-serif;
  --font-mono: 'JetBrains Mono', monospace;
  --text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.8rem);
  --text-sm: clamp(0.875rem, 0.8rem + 0.35vw, 0.95rem);
  --text-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
  --text-lg: clamp(1.125rem, 1rem + 0.6vw, 1.25rem);
  --text-2xl: clamp(1.5rem, 1.2rem + 1.5vw, 2rem);

  /* 간격 시스템 */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-12: 3rem;
  --space-16: 4rem;

  /* 그림자 */
  --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.05);
  --shadow-md: 0 4px 6px rgb(0 0 0 / 0.07);
  --shadow-lg: 0 10px 15px rgb(0 0 0 / 0.1);

  /* 레이아웃 */
  --container-max: 1200px;
  --radius-sm: 0.375rem;
  --radius-md: 0.5rem;
  --radius-lg: 0.75rem;
}

다크 모드 테마 전환

[data-theme="dark"] {
  --color-bg: #0f172a;
  --color-text: #e2e8f0;
  --color-text-muted: #94a3b8;
  --color-border: #334155;
  --color-surface: #1e293b;
  --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.3);
  --shadow-md: 0 4px 6px rgb(0 0 0 / 0.4);
}

/* 시스템 설정 자동 감지 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --color-bg: #0f172a;
    --color-text: #e2e8f0;
    --color-text-muted: #94a3b8;
    --color-border: #334155;
    --color-surface: #1e293b;
  }
}

컴포넌트 레벨 변수

/* 버튼 컴포넌트 */
.btn {
  --btn-bg: var(--color-primary-500);
  --btn-text: white;
  --btn-padding-x: var(--space-4);
  --btn-padding-y: var(--space-2);
  --btn-radius: var(--radius-md);

  background: var(--btn-bg);
  color: var(--btn-text);
  padding: var(--btn-padding-y) var(--btn-padding-x);
  border-radius: var(--btn-radius);
  font-size: var(--text-sm);
  transition: opacity 0.2s;
}

.btn:hover { opacity: 0.9; }
.btn--lg { --btn-padding-x: var(--space-6); --btn-padding-y: var(--space-3); }
.btn--danger { --btn-bg: #ef4444; }
.btn--outline {
  --btn-bg: transparent;
  --btn-text: var(--color-primary-500);
  border: 1px solid currentColor;
}

/* 카드 컴포넌트 */
.card {
  --card-padding: var(--space-6);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--card-padding);
  box-shadow: var(--shadow-sm);
}

.card--compact { --card-padding: var(--space-3); }
  • CSS 변수는 상속되므로 부모 요소에서 선언하면 자식에서 사용할 수 있습니다
  • var(--name, fallback)으로 폴백 값을 지정하여 안전하게 사용합니다
  • JavaScript의 getComputedStyle(el).getPropertyValue('--name')으로 값을 읽을 수 있습니다
  • clamp()와 조합하면 반응형 타이포그래피와 간격을 구현합니다
  • 컴포넌트 레벨 변수로 변형(variant)을 관리하면 CSS 양을 크게 줄일 수 있습니다

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록