CSS Custom Properties Syntax

CSS variable syntax, @property registration, fallbacks and cascade behavior.

Reference for CSS custom properties (--variable) syntax including var() fallbacks, the @property at-rule with syntax, inherits and initial-value, plus a live var() fallback resolver.

How do CSS custom property fallbacks work?

var(--name, fallback) uses the fallback only when --name is not set or is guaranteed-invalid. Fallbacks can nest, so var(--a, var(--b, red)) walks the chain and uses the first defined property, finally landing on the literal red if none are set.

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.