Variables are inherited, like color. A variable defined on an element is available to that element and all its descendants.
Global variables: :root
:root is the top element of the page, the same as html but with higher specificity. Variables defined there are available everywhere.
:root {
--brand: #d94a00;
}
Local variables: override inside a component
Redefine the variable on a more specific element, and only that element’s subtree changes.
<style>
:root { --accent: #1a5276; }
.btn { background: var(--accent); color: #fff; padding: 8px 16px; border: 0; border-radius: 6px; }
.warning { --accent: #d94a00; }
.warning, .plain { padding: 10px; margin: 6px 0; }
</style>
<div class="plain"><button class="btn">Default button</button></div>
<div class="warning"><button class="btn">Same class, inside .warning</button></div>
The .btn rule did not change. The variable it reads has a different value inside .warning. This is the technique behind component variants and themes.
Components with their own settings
A component can offer variables as an interface and use a fallback for the default:
.card {
padding: var(--card-padding, 1rem);
background: var(--card-bg, #fff);
}
.card.compact { --card-padding: 0.5rem; }
Changing variables with JavaScript
Scripts can update a variable and everything depending on it updates:
document.documentElement.style.setProperty('--brand', '#1a5276');
Variables inside media queries
You can change a variable at a breakpoint instead of rewriting rules:
:root { --gutter: 16px; }
@media (min-width: 768px) { :root { --gutter: 32px; } }
Naming
--color-primary, not --orange. That way a rebrand does not leave a --orange that is blue.