Skip to content
CSS

CSS Custom Properties (Variables) Guide

Master CSS variables for dynamic theming, component APIs, and maintainable design systems.

stellae.design

8 min read

Introduction

CSS Custom Properties (often called CSS variables) let you define reusable values directly in your stylesheets. Unlike preprocessor variables from Sass or Less, custom properties are live — they cascade, inherit, and can be manipulated with JavaScript at runtime.

This makes them incredibly powerful for theming, component APIs, and responsive design. Instead of duplicating values, you define them once and reference them everywhere. When the value changes, every reference updates automatically.

If you're building any kind of design system or maintaining a non-trivial codebase, custom properties aren't optional — they're essential infrastructure.


Key Concepts

Defining and Using Variables

css
:root {
  --color-primary: #3b82f6;
  --spacing-md: 1rem;
  --font-body: 'Inter', system-ui, sans-serif;
}

.button {
  background: var(--color-primary);
  padding: var(--spacing-md);
  font-family: var(--font-body);
}

Inheritance and Scope

css
.card {
  --card-padding: 1.5rem;
  padding: var(--card-padding);
}

.card--compact {
  --card-padding: 0.75rem;
}

Fallback Values

css
.element {
  color: var(--text-color, #333);
  gap: var(--custom-gap, var(--spacing-md, 1rem));
}

Practical Examples

1. Dark Mode Theming

css
:root { --bg: #fff; --text: #1a1a1a; }
[data-theme="dark"] { --bg: #0a0a0a; --text: #e5e5e5; }
body { background: var(--bg); color: var(--text); }

2. Component API

css
.avatar {
  --avatar-size: 3rem;
  width: var(--avatar-size);
  height: var(--avatar-size);
  border-radius: 50%;
}
.avatar--sm { --avatar-size: 2rem; }
.avatar--lg { --avatar-size: 5rem; }

3. Responsive Spacing

css
:root { --spacing-unit: 0.5rem; }
@media (min-width: 768px) { :root { --spacing-unit: 0.75rem; } }
.stack > * + * { margin-top: calc(var(--spacing-unit) * 3); }

4. JavaScript Integration

javascript
const primary = getComputedStyle(document.documentElement)
  .getPropertyValue('--color-primary');

document.documentElement.style
  .setProperty('--color-primary', '#ef4444');

Best Practices

  • Define design tokens as custom properties on :root for global access.
  • Use semantic names (--color-primary) over descriptive names (--blue-500).
  • Scope component-specific variables to the component selector, not :root.
  • Always provide fallback values when using variables that might not be defined.
  • Use calc() with custom properties for derived values.
  • Avoid deeply nesting var() calls — hurts readability and debugging.

Common Pitfalls

  1. Custom properties are case-sensitive: --Color and --color are different.
  2. Custom properties don't work in media query conditions.
  3. An invalid var() value uses the inherited value, not the fallback.
  4. Over-abstracting: not every value needs to be a variable.

Browser Support

Excellent support: Chrome 49+, Firefox 31+, Safari 9.1+, Edge 15+. Safe for production. Only IE11 lacks support.


CSScss

Was this article helpful?