I want to support light, dark and a brand theme without compiling separate stylesheets. Do CSS variables cascade and can JavaScript change them at runtime?
#css#custom-properties#theming
DEV3 Developer Forum
Every post is reviewed first. Usually reviewed within 24 hours.
I want to support light, dark and a brand theme without compiling separate stylesheets. Do CSS variables cascade and can JavaScript change them at runtime?
#css#custom-properties#theming
Custom properties are live and cascade
Sass variables are replaced at build time. CSS custom properties exist in the browser, inherit down the DOM, and can be changed at runtime or scoped to any element.
:root {
--bg: #ffffff;
--fg: #111827;
--accent: #2563eb;
--radius: 0.5rem;
}
[data-theme="dark"] {
--bg: #0b0f19;
--fg: #e5e7eb;
--accent: #60a5fa;
}
body { background: var(--bg); color: var(--fg); }
.btn { background: var(--accent); border-radius: var(--radius); }
Switching theme means changing one attribute: document.documentElement.dataset.theme = 'dark'. Every use updates instantly, with no re-render of your JS framework.
Fallbacks and scoping
.card { padding: var(--card-pad, 1rem); } /* default when undefined */
.card.compact { --card-pad: 0.5rem; } /* local override */
Update from JavaScript
el.style.setProperty('--progress', '0.4');
const v = getComputedStyle(el).getPropertyValue('--accent');
This is ideal for pointer-follow effects and progress bars (width: calc(var(--progress) * 100%)).
Typed, animatable variables
Plain variables are strings, so they cannot be transitioned. Register them:
@property --angle {
syntax: "<angle>";
inherits: false;
initial-value: 0deg;
}
.spinner { background: conic-gradient(from var(--angle), red, blue); animation: spin 2s linear infinite; }
@keyframes spin { to { --angle: 360deg; } }
Pitfalls
var(--color-blue-500)), so you can mix both approaches.