Variables that live in the cascade
CSS custom properties — informally CSS variables — let you store a value once and
reference it anywhere with var(). Unlike preprocessor variables they are real,
live values that participate in the cascade, inherit to descendants and can change
at runtime. This reference covers the declaration syntax, var() fallback rules,
the typed @property at-rule, and includes a resolver that mirrors how the browser
chooses a value from a nested fallback chain.
How it works
You declare a custom property on any selector and read it with var(), which
resolves at used-value time:
:root { --brand: #0a7; }
.btn { color: var(--brand, #333); }
The optional second argument to var() is a fallback used only when the property
is unset or guaranteed-invalid. Fallbacks nest, so the browser walks the chain and
uses the first defined property, falling back to the final literal. To give a
custom property a type — and the ability to animate — register it:
@property --angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
Notes and gotchas
Names are case-sensitive and require two leading dashes. An unregistered custom
property is essentially untyped (syntax: '*') and animates discretely. The
initial-value descriptor is required for any @property whose syntax is not
the universal *. Finally, a var() substitution that does not parse for the
consuming property is invalid at computed-value time and behaves as unset, which
is why a single bad variable can silently collapse to an inherited value.