Native variables in CSS
You made it to the last Web module, and we're opening it with one of those features that just feels good: CSS finally has real variables.
Custom properties (or CSS variables) are reusable values you
declare with a name starting with two dashes -- and read with the
var() function. Unlike the variables of a preprocessor like Sass,
they are dynamic: they live in the DOM, they cascade and they are inherited.
That one difference changes everything, as you'll see.
Declaring in :root
The usual place to define global variables is the pseudo-selector
:root, which represents the document (equivalent to <html> but with higher
specificity). This way they are available across the whole page.
:root {
--primary-color: #2563eb;
--text-color: #1f2937;
--space: 16px;
--radius: 8px;
}
Using with var()
.button {
background: var(--primary-color);
color: white;
padding: var(--space);
border-radius: var(--radius);
}
var() accepts a fallback value in case the variable is not defined:
.notice {
color: var(--notice-color, #b91c1c); /* uses #b91c1c if --notice-color does not exist */
}
Why they matter: theming and maintenance
Here's the gold. Without variables, changing your brand blue meant find-and-replace thirty times, praying you didn't miss one. With variables:
- A single point of change. If your brand goes from blue to green, you edit
--primary-coloronce in:rootand the whole interface updates. One line. - Dynamic themes. Since variables cascade, you can redefine them in a specific context (a class, an attribute, a media query) and everything that hangs from there changes its appearance without touching each rule.
:root { --background: white; --text: #111; }
[data-theme="dark"] {
--background: #0f172a;
--text: #e2e8f0;
}
body { background: var(--background); color: var(--text); }
Changing data-theme on <html> rewrites the variables and, with them, the whole
appearance. That is the basis of a maintainable dark mode: one attribute, a
thousand styles switching at once. The good kind of magic.