CSS Variables (Custom Properties): A Practical Guide
How to create and use CSS variables, why they beat preprocessor variables, and how to build theming and dark mode with them, with copy-paste examples.
- →CSS variables (custom properties) are defined with -- and read with the var() function.
- →They're usually declared on :root so they're available everywhere.
- →Unlike Sass variables, CSS variables are live in the browser and can change at runtime.
- →That live nature makes them perfect for theming and dark mode.
- →You can override them per component or per media query to change a whole design.
CSS variables, officially custom properties, let you store values like colors and spacing once and reuse them everywhere. Change one line and your whole design updates. They're also the cleanest way to build theming and dark mode. Here's how to use them well.
How to create a CSS variable
Declare a variable with two dashes, and read it with the var() function. Most people declare their variables on :root, the top of the document, so they're available everywhere.
:root {
--accent: #38bdf8;
--space: 1rem;
--radius: 12px;
}
.button {
background: var(--accent);
padding: var(--space);
border-radius: var(--radius);
}Now the accent color lives in one place. Change --accent and every element using it updates instantly.
Fallback values
var() accepts a second argument, a fallback used if the variable isn't defined. Handy for components that might be used outside your theme.
color: var(--text-color, #333); /* uses #333 if --text-color is unset */CSS variables vs Sass variables
If you've used Sass, you might wonder why CSS variables matter. The difference is huge: Sass variables are compiled away before the browser sees them, they're static. CSS variables are live in the browser, so they can change at runtime with JavaScript, media queries, or a class, which unlocks theming.
| Sass variable | CSS variable | |
|---|---|---|
| Exists at runtime? | No (compiled away) | Yes (live in browser) |
| Can change dynamically? | No | Yes |
| Good for theming? | Limited | Excellent |
| Needs a build step? | Yes | No |
Building dark mode with CSS variables
This is where CSS variables shine. Define your colors as variables, then override them under a dark-mode selector or media query. Nothing else in your CSS changes.
:root {
--bg: #ffffff;
--text: #111827;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #0b0f1a;
--text: #e5e7eb;
}
}
body { background: var(--bg); color: var(--text); }You can also toggle themes with a class (like <html data-theme="dark">) and override the variables under that selector. That lets users pick a theme manually, not just follow the system setting.
Scoping variables to components
Variables cascade like any CSS, so you can redefine one on a specific element to change just that subtree. Great for component variants without new class soup.
.card { --pad: 1rem; padding: var(--pad); }
.card.spacious { --pad: 2rem; } /* same rule, roomier variant */Define design tokens (colors, spacing, radius) as CSS variables once, and your whole UI becomes themeable and consistent with almost no extra code.
The short version
Create CSS variables with --name on :root and read them with var(--name). Unlike Sass variables, they're live in the browser, so you can override them for dark mode, themes and component variants at runtime. Use them for your design tokens and your CSS gets shorter and more flexible.
This site's entire theme, colors, spacing, radii, is built on CSS variables, which is how dark styling and accents stay consistent everywhere.
Frequently asked questions
How do I create a CSS variable?+
Declare it with two dashes, usually on :root so it's global: :root { --accent: #38bdf8; }. Then use it anywhere with the var() function: color: var(--accent). Changing the variable's value updates every element that uses it.
What's the difference between CSS variables and Sass variables?+
Sass variables are compiled away before the browser sees them, so they're static. CSS variables (custom properties) are live in the browser and can change at runtime via JavaScript, media queries or a class. That live nature makes CSS variables ideal for theming and dark mode.
How do I use CSS variables for dark mode?+
Define your colors as CSS variables on :root, then override those same variables under a dark-mode selector or a prefers-color-scheme: dark media query. Because your styles reference the variables, only the variable values change, and the whole UI switches themes.
Can CSS variables have fallback values?+
Yes. var() accepts a second argument used when the variable isn't defined: color: var(--text-color, #333). This is useful for components that might be used outside your theme, or to provide a safe default while a variable loads.
Can I change a CSS variable for just one component?+
Yes. CSS variables cascade, so you can redefine a variable on a specific element to affect only that element and its children. For example, set --pad on a .card, then override it on .card.spacious to create a roomier variant using the same rule.
I build fast, SEO-ready sites and rank them on Google and AI search.