Custom properties (informally "CSS variables") store a value once and reuse it, and — unlike a preprocessor variable (Sass/Less) — they're a real runtime feature the browser resolves live, which means they can change dynamically (via JavaScript, media queries, or :hover) without recompiling anything.
:root {
--primary-color: #0f8fa3;
--spacing-unit: 8px;
}
.button {
background: var(--primary-color);
padding: calc(var(--spacing-unit) * 2);
}
.button:hover {
--primary-color: #0b6f7f; /* reassigned locally — only affects .button and its descendants */
}
var(--name, fallback) accepts a second argument used if the custom property is unset:
.badge {
color: var(--badge-color, black); /* falls back to black if --badge-color was never defined */
}
Because custom properties participate in the cascade and inheritance like any other property, redefining --primary-color inside a .dark-theme class (rather than a global override) is the standard way to implement theming — every component that reads var(--primary-color) picks up the new value automatically, with no JavaScript required.