DevToolBox무료
블로그

고급 CSS 사용자 지정 속성: 테마, 컴포넌트 변형, JS 상호 운용

10분by DevToolBox

CSS Custom Properties는 단순한 색상 교체를 훨씬 넘어섰습니다. 이 가이드는 CSS Custom Properties를 현대 CSS의 가장 강력한 기능 중 하나로 만드는 고급 패턴을 탐구합니다.

Custom Properties 기초

Custom Properties는 -- 접두사로 정의되고 var() 함수로 접근합니다.

/* CSS Custom Properties — Fundamentals */

/* Define properties on :root for global scope */
:root {
  --color-primary: #0066cc;
  --color-primary-dark: #0052a3;
  --spacing-unit: 8px;
  --font-size-base: 1rem;
  --border-radius: 4px;
}

/* Use with var() */
.button {
  background-color: var(--color-primary);
  padding: calc(var(--spacing-unit) * 1.5) calc(var(--spacing-unit) * 3);
  border-radius: var(--border-radius);
  font-size: var(--font-size-base);
}

/* Override at component scope (not global) */
.button.danger {
  --color-primary: #cc0000;  /* Only affects this button */
  --color-primary-dark: #990000;
}

/* Fallback value (second argument to var) */
.card {
  background: var(--card-bg, white);
  color: var(--card-text, var(--color-text, #333));  /* nested fallback */
  padding: var(--card-padding, var(--spacing-unit, 8px));
}

Design Token 테마 시스템

Custom Properties의 가장 강력한 사용은 JavaScript 없이 여러 테마를 지원하는 완전한 디자인 토큰 시스템을 구축하는 것입니다.

/* Multi-Theme System with CSS Custom Properties */

/* Light theme (default) */
:root {
  --color-bg: #ffffff;
  --color-surface: #f8f9fa;
  --color-border: #e2e8f0;
  --color-text-primary: #1a202c;
  --color-text-secondary: #718096;
  --color-accent: #3182ce;
  --color-accent-hover: #2c5282;
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
  --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
  --transition-fast: 150ms ease;
}

/* Dark theme — override only what changes */
[data-theme="dark"] {
  --color-bg: #1a202c;
  --color-surface: #2d3748;
  --color-border: #4a5568;
  --color-text-primary: #f7fafc;
  --color-text-secondary: #a0aec0;
  --color-accent: #63b3ed;
  --color-accent-hover: #90cdf4;
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4);
  --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4);
}

/* High-contrast theme */
[data-theme="high-contrast"] {
  --color-bg: #000000;
  --color-text-primary: #ffffff;
  --color-accent: #ffff00;
  --color-border: #ffffff;
}

/* System preference auto-detection */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --color-bg: #1a202c;
    --color-text-primary: #f7fafc;
    /* ... more overrides */
  }
}

/* Components use semantic tokens — never raw colors */
.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  color: var(--color-text-primary);
  box-shadow: var(--shadow-md);
  transition: box-shadow var(--transition-fast);
}

Custom Properties를 사용한 컴포넌트 변형

Custom Properties는 전통적인 유틸리티 클래스보다 더 유연한 컴포넌트 변형 시스템을 가능하게 합니다.

/* Component Variant System */

/* Button component with custom property API */
.btn {
  /* Default values (the component's "API") */
  --btn-bg: var(--color-accent);
  --btn-bg-hover: var(--color-accent-hover);
  --btn-color: white;
  --btn-border: transparent;
  --btn-shadow: var(--shadow-sm);
  --btn-size: 1rem;
  --btn-padding-y: 0.5em;
  --btn-padding-x: 1em;
  --btn-radius: var(--border-radius);

  background: var(--btn-bg);
  color: var(--btn-color);
  border: 1px solid var(--btn-border);
  box-shadow: var(--btn-shadow);
  font-size: var(--btn-size);
  padding: var(--btn-padding-y) var(--btn-padding-x);
  border-radius: var(--btn-radius);
  transition: background var(--transition-fast);
}

.btn:hover {
  background: var(--btn-bg-hover);
}

/* Variants — only override what changes */
.btn-danger {
  --btn-bg: #e53e3e;
  --btn-bg-hover: #c53030;
}

.btn-outline {
  --btn-bg: transparent;
  --btn-bg-hover: var(--color-accent);
  --btn-color: var(--color-accent);
  --btn-border: var(--color-accent);
}

.btn-sm {
  --btn-size: 0.875rem;
  --btn-padding-y: 0.375em;
  --btn-padding-x: 0.75em;
}

.btn-lg {
  --btn-size: 1.125rem;
  --btn-padding-y: 0.75em;
  --btn-padding-x: 1.5em;
}

/* Caller overrides — no need for a new variant class */
.special-hero .btn {
  --btn-bg: gold;
  --btn-color: black;
  --btn-radius: 50px;
}

JavaScript 상호운용

Custom Properties는 CSS와 JavaScript를 원활하게 연결합니다.

// JavaScript <-> CSS Custom Properties

// 1. Read a custom property value
const root = document.documentElement;
const primaryColor = getComputedStyle(root)
  .getPropertyValue('--color-primary')
  .trim();
console.log(primaryColor); // '#0066cc'

// 2. Set a custom property from JavaScript
root.style.setProperty('--color-primary', '#ff6600');

// 3. Remove a custom property
root.style.removeProperty('--color-primary');

// 4. Theme switcher
function setTheme(theme) {
  document.documentElement.dataset.theme = theme;
  localStorage.setItem('theme', theme);
}

// 5. Animate with custom properties (requires @property)
// CSS:
// @property --progress {
//   syntax: '<number>';
//   initial-value: 0;
//   inherits: false;
// }
// .progress-bar {
//   width: calc(var(--progress) * 1%);
//   transition: --progress 1s ease;
// }

// JavaScript:
function animateProgress(el, from, to) {
  el.style.setProperty('--progress', from);
  requestAnimationFrame(() => {
    el.style.setProperty('--progress', to);
  });
}

// 6. Reactive properties with ResizeObserver
const observer = new ResizeObserver(entries => {
  for (const entry of entries) {
    const { width, height } = entry.contentRect;
    entry.target.style.setProperty('--el-width', `${width}px`);
    entry.target.style.setProperty('--el-height', `${height}px`);
  }
});
observer.observe(document.querySelector('.responsive-component'));

자주 묻는 질문

CSS Custom Properties는 SASS 변수와 같은가요?

아니요, 근본적으로 다릅니다. SASS 변수는 빌드 시 컴파일됩니다. CSS Custom Properties는 런타임에 존재하며 JavaScript로 변경할 수 있습니다.

CSS Custom Properties를 애니메이션할 수 있나요?

예, @property(Houdini)를 사용하면 가능합니다.

var()의 폴백 값이란?

var()의 두 번째 인수는 속성이 정의되지 않았을 때의 폴백입니다.

모든 현대 브라우저에서 작동하나요?

예, 2017년부터 모든 현대 브라우저에서 완전 지원됩니다.

관련 도구

𝕏 Twitterin LinkedIn
도움이 되었나요?

최신 소식 받기

주간 개발 팁과 새 도구 알림을 받으세요.

스팸 없음. 언제든 구독 해지 가능.

Try These Related Tools

🌈CSS Gradient Generator🎨Color Converter

Related Articles

CSS 변수(커스텀 프로퍼티) 완벽 가이드

CSS 커스텀 프로퍼티(변수) 마스터. 구문, 스코핑, 폴백 값, 다크 모드 테마, JavaScript 동적 업데이트.

CSS Grid 마스터: 2026년 실제 예제 완전 가이드

CSS Grid 레이아웃 마스터 2026: grid-template areas, 자동 배치, subgrid 및 반응형 레이아웃.

Tailwind CSS 컴포넌트 패턴: 2026년 유틸리티 클래스로 재사용 가능한 UI 구축

고급 Tailwind CSS 컴포넌트 패턴 2026: 디자인 토큰, 복합 컴포넌트, CSS-in-JS 없는 디자인 시스템.