Skip to main content

CSS Variables (Custom Properties)

Answer​

CSS Custom Properties (CSS Variables) allow you to define reusable values in CSS. They cascade like regular CSS properties and can be dynamically changed with JavaScript.

Syntax​

/* Define a variable */
:root {
--primary-color: #3498db;
--spacing-unit: 8px;
}

/* Use a variable */
.button {
background: var(--primary-color);
padding: var(--spacing-unit);
}

Variable Scope​

/* Global scope */
:root {
--primary: blue;
--secondary: green;
}

/* Component scope */
.card {
--card-padding: 20px;
}

/* Override in specific context */
.dark-theme {
--primary: lightblue;
--secondary: lightgreen;
}

Fallback Values​

.element {
/* If --accent not defined, use red */
color: var(--accent, red);

/* Fallback can be another variable */
background: var(--bg, var(--default-bg, white));

/* Fallback with complex value */
padding: var(--spacing, 16px 24px);
}

Theme Switching​

/* Light theme (default) */
:root {
--bg-color: #ffffff;
--text-color: #333333;
--border-color: #e0e0e0;
--shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

/* Dark theme */
[data-theme="dark"] {
--bg-color: #1a1a1a;
--text-color: #f0f0f0;
--border-color: #333333;
--shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
}

/* Components use variables - no duplication needed */
.card {
background: var(--bg-color);
color: var(--text-color);
border: 1px solid var(--border-color);
box-shadow: var(--shadow);
}
<!-- Toggle theme -->
<html data-theme="light">
<!-- or -->
<html data-theme="dark"></html>
</html>

Design System Example​

:root {
/* Colors */
--color-primary: #3498db;
--color-primary-dark: #2980b9;
--color-secondary: #2ecc71;
--color-danger: #e74c3c;
--color-warning: #f1c40f;

/* Typography */
--font-family: "Inter", system-ui, sans-serif;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.25rem;
--font-size-xl: 1.5rem;

/* Spacing scale */
--space-1: 4px;
--space-2: 8px;
--space-3: 16px;
--space-4: 24px;
--space-5: 32px;

/* Border radius */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 16px;
--radius-full: 9999px;

/* Shadows */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.1);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 20px rgba(0, 0, 0, 0.15);

/* Transitions */
--transition-fast: 150ms ease;
--transition-base: 300ms ease;
}

JavaScript Interaction​

// Get variable value
const styles = getComputedStyle(document.documentElement);
const primary = styles.getPropertyValue("--primary-color");

// Set variable value
document.documentElement.style.setProperty("--primary-color", "#ff6b6b");

// Set on specific element
element.style.setProperty("--custom-width", "200px");

// Theme toggle
function toggleTheme() {
const html = document.documentElement;
const currentTheme = html.getAttribute("data-theme");
html.setAttribute("data-theme", currentTheme === "dark" ? "light" : "dark");
}

Calculations with CSS Variables​

:root {
--base-size: 16px;
--scale: 1.25;
}

h1 {
/* Calculate using var in calc() */
font-size: calc(
var(--base-size) * var(--scale) * var(--scale) * var(--scale)
);
}

.grid {
--columns: 3;
--gap: 20px;

display: grid;
grid-template-columns: repeat(var(--columns), 1fr);
gap: var(--gap);
}

/* Responsive adjustments */
@media (max-width: 768px) {
.grid {
--columns: 2;
--gap: 15px;
}
}

Component-Based Variables​

/* Button component with internal variables */
.button {
--btn-padding-x: 16px;
--btn-padding-y: 8px;
--btn-bg: var(--color-primary);
--btn-color: white;

padding: var(--btn-padding-y) var(--btn-padding-x);
background: var(--btn-bg);
color: var(--btn-color);
}

/* Size variants */
.button--small {
--btn-padding-x: 12px;
--btn-padding-y: 4px;
}

.button--large {
--btn-padding-x: 24px;
--btn-padding-y: 12px;
}

/* Color variants */
.button--danger {
--btn-bg: var(--color-danger);
}

.button--outline {
--btn-bg: transparent;
--btn-color: var(--color-primary);
border: 2px solid currentColor;
}

Browser Support & Fallbacks​

.element {
/* Fallback for old browsers */
color: blue;
/* Modern browsers */
color: var(--primary-color, blue);
}

/* Or use @supports */
@supports (--css: variables) {
.element {
color: var(--primary-color);
}
}

Key Points​

  • Define with --name, use with var(--name)
  • Scope to :root for global, element for local
  • Variables cascade and can be overridden
  • Provide fallbacks: var(--name, fallback)
  • Can be modified with JavaScript
  • Perfect for theming and design systems
  • Work inside calc() for dynamic calculations