CSS custom properties — often called CSS variables — let you define reusable values in one place and reference them throughout your stylesheet. Unlike preprocessor variables (Sass/LESS), they are live in the browser: JavaScript can read and write them, and they respect the cascade and inheritance.
Problem: How do you define reusable values in CSS — such as brand colours or spacing units — so you can update them in one place and have the change propagate everywhere?
Solution: Use CSS custom properties — declare them on :root with the -- prefix and read them with var(). Unlike preprocessor variables, they cascade and can be overridden per element at runtime without a build step.
Define variables on the :root element to make them globally available:
:root {
--color-primary: #3498db;
--color-secondary: #2ecc71;
--color-text: #333;
--font-base: 'Open Sans', sans-serif;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 2rem;
--radius: 4px;
}
.btn {
background: var( --color-primary );
color: #fff;
padding: var( --spacing-sm ) var( --spacing-md );
border-radius: var( --radius );
font-family: var( --font-base );
}
.btn:hover {
/* Fallback value if the variable is not defined */
background: var( --color-hover, #2980b9 );
}
Override variables in a scoped context — great for themes and dark mode:
.theme-dark {
--color-primary: #1a1a2e;
--color-text: #e0e0e0;
}
/* All components inside .theme-dark automatically pick up the new values */
Read and update variables from JavaScript:
// Read
const primary = getComputedStyle( document.documentElement )
.getPropertyValue( '--color-primary' ).trim();
// Write
document.documentElement.style.setProperty( '--color-primary', '#e74c3c' );
NOTE: CSS custom properties are case-sensitive: --Color-Primary and --color-primary are different variables. Browser support for custom properties has been solid since early 2017 — Edge 15, Chrome 49, Firefox 31, Safari 9.1 all support them. For IE11 support, you'll need a polyfill or a PostCSS transform.