CSS Custom Properties
Defining reusable values with --variables and reading them with var, including how they cascade and update live.
阅读需 2 分钟
CSS custom properties (informally called "CSS variables") let you define a value once and reuse it throughout a stylesheet — and unlike a preprocessor variable, they're a real, live feature of the browser itself.
Defining and using a custom property
:root {
--brand-color: #2563eb;
--spacing-unit: 8px;
}
.button {
background: var(--brand-color);
padding: calc(var(--spacing-unit) * 2);
}
.link {
color: var(--brand-color);
}A custom property name always starts with two dashes (--brand-color). Defining it on :root (a selector matching the <html> element) makes it available globally, since custom properties inherit down through the whole document like any other inheritable CSS value. var(--brand-color) reads the value back wherever it's needed — change the definition once, and every usage updates.
Fallback values
.badge {
color: var(--badge-color, #6b7280);
}var() accepts a second argument used if the custom property isn't defined (or was set to an invalid value) — here, .badge falls back to gray if --badge-color was never set anywhere in scope. This makes components more robust when they're reused in a context that hasn't defined every variable they expect.
Custom properties cascade and can be overridden per scope
:root {
--card-padding: 16px;
}
.card {
padding: var(--card-padding);
}
.card.compact {
--card-padding: 8px;
}Because custom properties follow the normal cascade, redefining --card-padding inside .card.compact changes what var(--card-padding) resolves to for that element and its descendants, without touching the global default. This is a fundamentally different mechanism from a Sass/Less variable, which is resolved once at compile time and can't vary per element at runtime.
A real use case: theming
:root {
--bg: white;
--text: #111827;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #0f172a;
--text: #e2e8f0;
}
}
body {
background: var(--bg);
color: var(--text);
}Because the values live in real, live CSS, a single media query (or a class toggled by JavaScript, like .dark-mode) can redefine a handful of custom properties and instantly re-theme every element that references them — no need to rewrite every individual rule for dark mode.
Reading and writing from JavaScript
.progress-bar {
width: var(--progress, 0%);
}document.querySelector(".progress-bar").style.setProperty("--progress", "60%");Custom properties can also be set from JavaScript on a specific element, making them a clean bridge between dynamic, script-driven values (like a progress percentage) and static CSS rules — the CSS doesn't need to know what the specific value is, only that it should use whatever --progress currently holds.