DevToolBoxGRATIS
Blog

CSS Custom Properties Lanjutan: Tema, Varian Komponen dan Interop JS

10 menitoleh DevToolBox

CSS Custom Properties telah berkembang jauh melampaui penggantian warna sederhana. Panduan ini mengeksplorasi pola lanjutan yang menjadikan CSS Custom Properties salah satu fitur paling kuat dalam CSS modern.

Dasar-dasar Custom Properties

Custom Properties didefinisikan dengan prefiks -- dan diakses dengan fungsi 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));
}

Sistem Theming Design Token

Penggunaan paling kuat dari Custom Properties adalah membangun sistem design token lengkap yang mendukung beberapa tema tanpa 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);
}

Varian Komponen dengan Custom Properties

Custom Properties memungkinkan sistem varian komponen yang lebih fleksibel dari pendekatan kelas utilitas tradisional.

/* 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;
}

Interoperabilitas JavaScript

Custom Properties menjembatani CSS dan JavaScript dengan mulus.

// 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'));

Pertanyaan yang Sering Diajukan

Apakah CSS Custom Properties sama dengan variabel SASS?

Tidak, keduanya berbeda secara fundamental. Variabel SASS dikompilasi saat build. CSS Custom Properties ada saat runtime.

Bisakah CSS Custom Properties dianimasikan?

Ya, dengan @property (Houdini).

Apa nilai fallback di var()?

Argumen kedua var() adalah fallback yang digunakan ketika properti tidak terdefinisi.

Apakah berfungsi di semua browser modern?

Ya, dukungan penuh sejak 2017.

Alat Terkait

𝕏 Twitterin LinkedIn
Apakah ini membantu?

Tetap Update

Dapatkan tips dev mingguan dan tool baru.

Tanpa spam. Berhenti kapan saja.

Coba Alat Terkait

🌈CSS Gradient Generator🎨Color Converter

Artikel Terkait

Variabel CSS (Custom Properties): Panduan Lengkap

Kuasai CSS custom properties. Sintaks, scoping, nilai fallback, dan tema dark mode.

CSS Grid Mastery: Panduan Lengkap dengan Contoh Nyata 2026

Kuasai CSS Grid Layout 2026: grid-template areas, penempatan otomatis, subgrid dan layout responsif.

Pola Komponen Tailwind CSS: Membangun UI yang Dapat Digunakan Kembali di 2026

Pola komponen Tailwind CSS tingkat lanjut 2026: design tokens, komponen gabungan dan sistem desain tanpa CSS-in-JS.