CSS variables
On a site the same brand color appears in dozens of rules. To change it, you would have to edit every one of them. CSS variables (officially, custom properties) solve this: a value is written once under a clear name and used anywhere.
Declaring and var()
A variable name starts with two hyphens. It is declared like a regular property and read with the var() function:
<style>
.card {
--accent: tomato;
border: 2px solid var(--accent);
color: var(--accent);
padding: 8px;
}
</style>
<div class="card">The border and the text share one color</div>Replace tomato with another color in one place, and both the border and the text change.
Global variables
Variables are inherited, like text color: they apply to an element and everything inside it. That is why shared values are declared in :root — a pseudo-class that picks the root <html> element. This way the variables are available on the whole page:
<style>
:root {
--brand: rebeccapurple;
--radius: 8px;
}
.button {
padding: 8px 16px;
border: 0;
border-radius: var(--radius);
background: var(--brand);
color: white;
}
h3 { color: var(--brand); }
</style>
<h3>A heading</h3>
<button class="button">A button</button>Overriding
A variable can be overridden for part of the page. The new value applies inside the element where it is set, and other elements do not see it:
<style>
:root { --brand: rebeccapurple; }
.danger { --brand: crimson; }
.button {
padding: 8px 16px;
border: 0;
background: var(--brand);
color: white;
}
</style>
<button class="button">Regular</button>
<button class="button danger">Dangerous</button>The button rule is the same — only the value of the variable changed. This is how themes and component variants are made.
Fallback value
The second argument of var() is a value to use if the variable is not declared:
<style>
.note {
background: var(--note-bg, lightyellow);
padding: 8px;
}
</style>
<p class="note">There is no --note-bg variable, so the fallback color is used.</p>Variables in calculations
Numbers from variables can be used in the calc() function, which computes values. This way sizes are built from one base:
<style>
:root { --space: 8px; }
.box {
padding: var(--space);
margin-bottom: calc(var(--space) * 3);
background: lavender;
}
</style>
<div class="box">8px of padding inside</div>
<div class="box">and 24px between the blocks</div>More about calc() and other functions is in the chapter on modern CSS. The same chapter has a lesson on @property: it gives a variable a type, so it can be animated.
Common mistake
A variable name on its own does not insert the value — you need the var() function. Also, names are case-sensitive: --Brand and --brand are different variables:
<style>
:root { --brand: seagreen; }
.a { color: --brand; }
.b { color: var(--Brand); }
.c { color: var(--brand); }
</style>
<p class="a">color: --brand — did not work</p>
<p class="b">var(--Brand) — a different name, did not work</p>
<p class="c">var(--brand) — green</p>