CSS Custom Properties (Variables): The Complete Guide
Master CSS custom properties: declare, inherit, scope, fallback values, dark mode theming, and responsive design with native CSS variables.
- Master CSS custom properties: declare, inherit, scope, fallback values, dark mode theming, and responsive design with native CSS variables.
- What Are Custom Properties?.
- Covers declaring & using variables.
- Covers scope & inheritance.
- Covers fallback values.
What Are Custom Properties?
CSS custom properties โ commonly called CSS variables โ let you store values in one place and reference them throughout your stylesheet. They're native to the browser, require no build step, and support features that preprocessor variables can't match: cascade, inheritance, runtime changes, and JavaScript interaction.
Custom properties were a missing piece in CSS for over a decade. Sass and LESS filled the gap with compile-time variables, but those variables vanish after the build โ they can't be changed at runtime, don't cascade through the DOM, and can't be read or modified with JavaScript. CSS custom properties solve all three problems.
Declaring & Using Variables
Declare a custom property with a double-hyphen prefix. Reference it with the var() function:
auto-fill and auto-fit behave differently when there are fewer items than columns. Use auto-fill to keep empty tracks; auto-fit to collapse them.The :root selector targets the element, making these variables available everywhere in the document. You can also declare variables on any element to limit their scope.
Scope & Inheritance
Custom properties follow the same cascade and inheritance rules as any CSS property. A variable declared on a parent element is available to all its children. A variable declared on a more specific selector overrides the inherited value within that subtree.
width, height, top, or left. These trigger layout recalculations on every frame and can drop performance below 60fps.A .card inside .dark-section uses the dark background; a .card outside it uses white. This scoping behavior is what makes CSS variables so powerful for theming โ you change the variable at a container level and everything inside adapts automatically.
Variables declared on a pseudo-class like :hover or :focus apply only when that state is active, enabling dynamic state-driven styling without JavaScript.
Fallback Values
The var() function accepts a second argument as a fallback value. If the variable isn't defined in the current scope, the fallback is used:
Fallbacks can also reference other variables:
This chaining pattern is useful for component libraries where a consumer might or might not define a theme variable. The component uses the theme variable if present, falls back to its own default, and uses a safe final value as a last resort.
Dark Mode Theming
CSS custom properties make dark mode implementation clean and maintainable. Define your color palette as variables, then override them inside a prefers-color-scheme media query or a .dark class:
Every component that references these variables switches themes automatically โ no component-level CSS changes needed. This approach scales from a personal blog to a design system with hundreds of components.
Responsive Design with Variables
You can redefine custom properties inside media queries to create responsive systems without duplicating property declarations:
Components reference these variables once and adapt at every breakpoint. This dramatically reduces the number of media queries scattered across your stylesheet.
Accessing Variables from JavaScript
Unlike preprocessor variables, CSS custom properties exist at runtime and can be read and written with JavaScript:
This enables powerful patterns like user-configurable themes, scroll-driven animations, and cursor-following effects โ all driven by a single CSS variable that JavaScript updates and CSS consumes.
CSS Variables vs Sass/LESS Variables
Sass and LESS variables are compile-time: they're resolved during the build and replaced with static values. They can't change at runtime, don't respect the DOM cascade, and aren't accessible to JavaScript. But they do support math operations and more complex logic during compilation.
CSS custom properties are runtime: they exist in the browser, cascade through the DOM, and can be changed dynamically. They don't support complex math (though calc() works), and they can't be used in selectors or media query conditions.
In practice, most modern projects use CSS custom properties for theming and design tokens, and preprocessor variables for build-time configuration like breakpoint values and mixin parameters.
Best Practices
Name semantically, not visually. Use `--color-primary` instead of `--blue`. When your brand color changes from blue to purple, semantic names still make sense.
Use a consistent naming convention. Common patterns include `--category-property-variant` (e.g., `--color-text-muted`, `--spacing-lg`) or BEM-style nesting.
Keep `:root` variables to design tokens only. Component-specific variables should be scoped to the component's selector, not polluting the global namespace.
Document your variables. A comment block listing all available variables with their purpose is invaluable for team projects. Or better yet, use the CSS Variable Generator to build and export a documented variable system.
Frequently Asked Questions
What are CSS custom properties?
Can I use CSS variables in media queries?
Do CSS variables work in all browsers?
What is the var() fallback?
Use the CSS Variable Generator โ free, no signup required.
โก Open CSS Variable Generator