Store reusable design values in the cascade
CSS custom properties use names beginning with -- and are read with var(). Unlike preprocessor variables, they participate in the browser's cascade and can change by scope or state at runtime.
:root {
--color-brand: #1d4ed8;
--space-card: 1.25rem;
--radius-card: 0.75rem;
}
.card {
padding: var(--space-card);
border-radius: var(--radius-card);
border: 1px solid var(--color-brand);
}
.card--compact { --space-card: 0.75rem; }
.card__link { color: var(--color-brand, #172554); }A compact card overrides the spacing token within its subtree. The fallback color is used when the referenced custom property is missing or invalid in the relevant var-resolution sense. A custom property containing a value of the wrong type for color can still invalidate the final declaration; a fallback is not a universal type validator.
Scope and inheritance
Unregistered custom properties normally inherit. A token on a component can influence its descendants without changing unrelated components. Names are case-sensitive. Use descriptive names such as --surface-card instead of numbers whose meaning disappears during maintenance.
Calculations
.panel { padding: calc(var(--space-card) * 2); }Math still needs valid units and compatible values. Do not construct a unit by concatenating arbitrary token text and assume the browser will parse it as a length. Store the full value, such as 1rem, or use a valid calculation.
Tokens are not secrets
Custom properties are part of the page's styles and can be inspected. Never store credentials or private data in them. They are a design and behavior mechanism, not secure storage.
Practice
- Change the brand token and verify borders and links update together.
- Override spacing on one compact card without affecting its neighbor.
- Remove a token to observe a deliberate fallback.
- Give a color token an invalid value and inspect the computed declaration rather than assuming the fallback always repairs it.