Advanced20 min read

CSS Custom Properties

Learn how to define and use CSS custom properties (variables) with the -- syntax and var() function for maintainable, themeable stylesheets.

What Are CSS Custom Properties?

CSS custom properties (often called CSS variables) let you define reusable values that can be referenced throughout your stylesheet. They are declared with a double-hyphen prefix -- and read with the var() function.

Why use custom properties?

  • Single source of truth — Change a color in one place and it updates everywhere it is used.
  • Theming — Switch entire color schemes by changing a few variables.
  • Readabilityvar(--primary-color) is more meaningful than #3498db.
  • Dynamic updates — Unlike preprocessor variables (Sass/Less), CSS custom properties are live in the browser and can be updated with JavaScript.

Declaring variables

Variables are declared on a selector. The most common place is :root (equivalent to <html>) so they are available globally:

css
:root {
  --primary-color: #3498db;
  --spacing-md: 16px;
  --font-main: "Inter", sans-serif;
}

Using variables

Reference a variable with var():

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

Custom Properties in Practice

html
<style>
  :root {
    --primary: #3498db;
    --secondary: #2ecc71;
    --text-color: #333;
    --bg-color: #ffffff;
    --radius: 8px;
    --spacing: 16px;
  }

  body {
    color: var(--text-color);
    background-color: var(--bg-color);
    font-family: sans-serif;
    padding: var(--spacing);
  }

  .card {
    border: 2px solid var(--primary);
    border-radius: var(--radius);
    padding: var(--spacing);
    margin-bottom: var(--spacing);
  }

  .card h3 {
    color: var(--primary);
  }

  .btn {
    background-color: var(--secondary);
    color: white;
    border: none;
    padding: 8px var(--spacing);
    border-radius: var(--radius);
    cursor: pointer;
  }
</style>

<div class="card">
  <h3>CSS Variables</h3>
  <p>Change --primary to update all blue elements at once.</p>
  <button class="btn">Click Me</button>
</div>

Fallbacks, Scope, and JavaScript

Fallback values

The var() function accepts an optional second argument — a fallback value used if the variable is not defined:

css
color: var(--accent-color, #e74c3c);

If --accent-color is not defined in any ancestor, #e74c3c is used instead.

Scope and inheritance

Custom properties follow the normal cascade and inherit down the DOM tree. You can override a variable for a specific subtree:

css
:root { --bg: white; }
.dark-section { --bg: #1a1a1a; }

.card {
  background: var(--bg);
  /* White in general, dark inside .dark-section */
}

Updating with JavaScript

Because custom properties are live, you can update them at runtime:

javascript
// Change a global variable
document.documentElement.style.setProperty('--primary', '#e74c3c');

// Change a scoped variable
element.style.setProperty('--card-bg', '#f0f0f0');

This makes CSS variables the foundation of dynamic theming — you can build a complete dark mode toggle without changing any CSS selectors.

What happens when you use `var(--undefined-var, blue)` and `--undefined-var` is not declared anywhere?

Ready to practice?

Create your free account to access the interactive code editor, run challenges, and track your progress.