CSS custom properties (also called CSS variables) are now supported in all major browsers, except IE. They're fundamentally different from Sass variables and have their own unique advantages worth understanding properly.
Basic Syntax
/* Define variables: prefix with -- */
:root {
--primary-color: #409eff;
--font-size-base: 14px;
--spacing-md: 16px;
}
/* Use variables: var() function */
.button {
background-color: var(--primary-color);
font-size: var(--font-size-base);
padding: var(--spacing-md);
}
/* Can provide a fallback value */
.text {
color: var(--text-color, #333); /* uses #333 if --text-color is undefined */
}
The Fundamental Difference from Sass Variables
Sass variables are compile-time and disappear after compilation:
// Sass variable
$primary: #409eff;
.btn {
color: $primary;
}
// Compiled output
.btn {
color: #409eff;
}
// The variable no longer exists at runtime — can't be changed dynamically
CSS variables exist at runtime:
/* CSS variables live at runtime and can be changed dynamically */
:root { --primary: #409eff; }
.btn { color: var(--primary); }
/* JavaScript can modify them */
document.documentElement.style.setProperty('--primary', '#67c23a')
/* All elements using var(--primary) update immediately */
This is the biggest advantage of CSS variables: runtime dynamic modification.
Use Case 1: Theme Switching
Before CSS variables, implementing theme switching required either pre-compiling multiple CSS files or swapping classes with JavaScript. CSS variables make it much simpler:
/* Define themes */
:root {
--bg-color: #ffffff;
--text-color: #333333;
--primary: #409eff;
}
[data-theme="dark"] {
--bg-color: #1a1a2e;
--text-color: #e0e0e0;
--primary: #64b5f6;
}
/* All components only use variables — no hard-coded colors */
body {
background: var(--bg-color);
color: var(--text-color);
}
// Switch themes
document.documentElement.setAttribute("data-theme", "dark");
document.documentElement.setAttribute("data-theme", "light");
Use Case 2: Dynamic Spacing/Sizing
In responsive layouts, spacing can change with screen size:
:root {
--spacing: 16px;
}
@media (max-width: 768px) {
:root {
--spacing: 8px;
}
}
.card {
padding: var(--spacing);
margin-bottom: var(--spacing);
}
.card-header {
padding: calc(var(--spacing) / 2) var(--spacing);
}
Use Case 3: Component-level Variables (Local Scope)
CSS variables follow CSS inheritance rules and can be overridden within a component:
/* Global defaults */
:root {
--button-bg: #409eff;
--button-radius: 4px;
}
/* Override within a specific context */
.danger-zone {
--button-bg: #f56c6c;
}
/* All buttons inside .danger-zone will use the red background */
.button {
background: var(--button-bg);
border-radius: var(--button-radius);
}
This pattern is especially useful for component library theme customization:
/* Users can override a component's default style variables */
.my-app {
--el-color-primary: #722ed1; /* Custom Element UI theme color */
}
Using CSS Variables with Sass
In real projects you can combine both: Sass handles compile-time logic (loops, conditionals, functions); CSS variables handle runtime dynamism.
// Use Sass to generate CSS variables in bulk
$colors: (
"primary": #409eff,
"success": #67c23a,
"warning": #e6a23c,
"danger": #f56c6c,
);
:root {
@each $name, $value in $colors {
--color-#{$name}: #{$value};
}
}
Reading and Writing CSS Variables with JavaScript
// Read
const value = getComputedStyle(document.documentElement)
.getPropertyValue("--primary-color")
.trim();
// Set
document.documentElement.style.setProperty("--primary-color", "#67c23a");
// Delete (restores the inherited value)
document.documentElement.style.removeProperty("--primary-color");
// Set locally within a component
element.style.setProperty("--button-size", "32px");
Browser Support
As of early 2018, all major browsers support CSS variables: Chrome 49+, Firefox 31+, Safari 9.1+, Edge 15+. Only IE is unsupported.
If IE support is required, use postcss-custom-properties to replace variables with concrete values at compile time (losing the dynamic capability, but ensuring compatibility).
Summary
- The core value of CSS variables is runtime dynamism — something Sass variables cannot provide
- Theme switching, responsive design, and component theme customization are the best use cases
- Variables follow CSS inheritance rules and can be overridden at any scope
- Combine with Sass: Sass for compile-time logic, CSS variables for runtime flexibility