CSS course menu
CSS Custom Properties (CSS Variables): var(), Fallbacks, Scope and Theming
Learn CSS custom properties (variables): declaring --name values, using var() with fallbacks, global and local scope, inheritance, overriding variables in components and media queries, design tokens, changing them with JavaScript, and @property.
On this page
Custom properties, usually called CSS variables, store a value once and reuse it everywhere. Change the variable and every place that uses it updates.
Declaring and using variables#
:root {
--brand: #2f5fe0;
--radius: 10px;
--space: 12px;
}
.btn {
padding: var(--space) calc(var(--space) * 2);
background: var(--brand);
color: white;
border: none;
border-radius: var(--radius);
}
.card {
margin-top: var(--space);
padding: var(--space);
border: 2px solid var(--brand);
border-radius: var(--radius);
}<button class="btn">Brand button</button>
<div class="card">A card using the same colour, radius and spacing.</div>- A custom property name starts with two hyphens:
--brand. Names are case-sensitive. var(--brand)reads its value.:rootis the<html>element, so variables set there are available everywhere.
Fallback values#
var() takes an optional fallback, used when the variable is not set:
color: var(--text-color, #222);
padding: var(--card-padding, var(--space, 16px)); /* fallbacks can nest */Scope and inheritance#
Custom properties are inherited and can be set on any element. A component can override a variable for itself and everything inside it:
:root { --accent: #2f5fe0; }
.badge { display: inline-block; padding: 4px 10px; border-radius: 999px; background: var(--accent); color: white; }
.danger { --accent: #c92a2a; }
.success { --accent: #2f9e44; }<p><span class="badge">Default</span></p>
<div class="danger"><span class="badge">Inside .danger</span></div>
<div class="success"><span class="badge">Inside .success</span></div>The .badge rule never changes; only the variable it reads does. This is the basis of theming and component variants.
Variables in media queries#
You cannot use a variable inside a media query condition (@media (min-width: var(--bp)) does not work), but you can change variables within media queries:
:root { --gutter: 16px; }
@media (min-width: 800px) {
:root { --gutter: 32px; }
}
.container { padding-inline: var(--gutter); }Design tokens#
Many teams keep all their design decisions in variables, often called design tokens:
:root {
/* Colours */
--color-bg: #ffffff;
--color-text: #1f2328;
--color-primary: #2f5fe0;
/* Spacing scale */
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 1rem;
--space-4: 2rem;
/* Typography */
--font-sans: system-ui, sans-serif;
--text-sm: 0.875rem;
--text-lg: 1.25rem;
}Using tokens everywhere keeps a design consistent, and switching the values (for a dark theme or a rebrand) re-themes the whole site. Dark Mode builds on exactly this.
Changing variables with JavaScript#
<label>Hue <input type="range" min="0" max="360" value="220" id="hue"></label>
<div id="swatch" style="height: 50px; margin-top: 8px; border-radius: 8px; background: hsl(var(--hue, 220) 70% 50%)"></div>const slider = document.getElementById("hue");
slider.addEventListener("input", () => {
document.getElementById("swatch").style.setProperty("--hue", slider.value);
});element.style.setProperty("--name", value) sets a variable, and getComputedStyle(element).getPropertyValue("--name") reads one.
Things to know#
- A variable holds raw text until it is used.
--size: 20and thenwidth: var(--size)pxdoes not work; write--size: 20px, orcalc(var(--size) * 1px). - If a variable contains a value that is invalid where it is used, the property falls back to its inherited or initial value, not to an earlier declaration.
@propertycan register a variable with a type, initial value and inheritance, which also lets browsers animate it:
@property --angle {
syntax: "<angle>";
inherits: false;
initial-value: 0deg;
}Practice#
Practice exercise
Create a .alert component that uses --alert-color for its left border and its heading colour, with a default of blue, and .alert-warning and .alert-error variants that only change the variable.
Show solution
.alert {
--alert-color: #2f5fe0;
border-left: 5px solid var(--alert-color);
background: #f8f9fa;
padding: 8px 12px;
margin-bottom: 8px;
}
.alert strong { color: var(--alert-color); }
.alert-warning { --alert-color: #e67700; }
.alert-error { --alert-color: #c92a2a; }<div class="alert"><strong>Info:</strong> Classes start at 10 am.</div>
<div class="alert alert-warning"><strong>Warning:</strong> Only 3 seats left.</div>
<div class="alert alert-error"><strong>Error:</strong> Payment failed.</div>Key takeaway#
Finished this lesson?