CSS Variables (Custom Properties)

CSS variables (custom properties) let you store reusable values and create dynamic, maintainable stylesheets.

Defining and Using Variables

CSS
/* Define in :root (available everywhere) */
:root {
    --primary: #3b82f6;
    --primary-dark: #2563eb;
    --text: #1f2937;
    --text-light: #6b7280;
    --bg: #ffffff;
    --bg-surface: #f9fafb;
    --border: #e5e7eb;
    --radius: 8px;
    --shadow: 0 1px 3px rgba(0,0,0,0.1);
    --spacing: 16px;
    --font-sans: system-ui, -apple-system, sans-serif;
}

/* Use with var() */
.button {
    background: var(--primary);
    color: white;
    border-radius: var(--radius);
    padding: var(--spacing);
    font-family: var(--font-sans);
}

/* Fallback values */
.element {
    color: var(--custom-color, #333);  /* Falls back to #333 */
}

Scoped Variables

CSS
/* Variables can be scoped to any element */
.card {
    --card-bg: white;
    --card-padding: 24px;
    background: var(--card-bg);
    padding: var(--card-padding);
}

.card.dark {
    --card-bg: #1f2937;  /* Override for dark variant */
}

/* Inherit and override */
.sidebar {
    --sidebar-width: 250px;
    width: var(--sidebar-width);
}

.sidebar.collapsed {
    --sidebar-width: 60px;  /* Override */
}

Dynamic Theming

CSS
/* Light theme (default) */
:root {
    --bg: #ffffff;
    --text: #1f2937;
    --primary: #3b82f6;
}

/* Dark theme */
[data-theme="dark"] {
    --bg: #111827;
    --text: #f9fafb;
    --primary: #60a5fa;
}

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

body {
    background: var(--bg);
    color: var(--text);
}

a { color: var(--primary); }
JavaScript
// Toggle theme with JavaScript
document.documentElement.dataset.theme = 
    document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark';

Practical Patterns

CSS
/* Typography scale */
:root {
    --text-xs: 0.75rem;
    --text-sm: 0.875rem;
    --text-base: 1rem;
    --text-lg: 1.125rem;
    --text-xl: 1.25rem;
    --text-2xl: 1.5rem;
    --text-3xl: 1.875rem;
    --text-4xl: 2.25rem;
}

body { font-size: var(--text-base); }
h1 { font-size: var(--text-4xl); }
h2 { font-size: var(--text-3xl); }
h3 { font-size: var(--text-2xl); }
small { font-size: var(--text-sm); }

/* Spacing scale */
:root {
    --space-1: 0.25rem;   /* 4px */
    --space-2: 0.5rem;    /* 8px */
    --space-3: 0.75rem;   /* 12px */
    --space-4: 1rem;      /* 16px */
    --space-6: 1.5rem;    /* 24px */
    --space-8: 2rem;      /* 32px */
}

.card { padding: var(--space-6); }
.gap { gap: var(--space-4); }

/* Responsive with variables */
:root {
    --container-max: 1200px;
    --gutter: 16px;
}

@media (min-width: 768px) {
    :root {
        --gutter: 24px;
    }
}

.container {
    max-width: var(--container-max);
    padding: 0 var(--gutter);
}

Knowledge Check

4 questions — test your understanding

1

Where should you define global CSS variables?

2

What does `var(--color, #333)` do if --color is not defined?

3

Can CSS variables be changed dynamically?

4

What is the benefit of a spacing scale using CSS variables?