CSS variables (officially called CSS custom properties) are one of the most powerful features in modern CSS. They let you define reusable values that can be updated dynamically, making your stylesheets more maintainable and your design systems more flexible.
What Are CSS Variables?
CSS variables are entities defined by CSS authors that contain specific values to be reused throughout a document. They're set using custom property notation (e.g., --main-color: black;) and accessed using the var() function (e.g., color: var(--main-color);).
Unlike preprocessor variables (Sass, Less), CSS variables are part of the DOM. This means they can be manipulated with JavaScript, respond to media queries, and cascade through your document just like any other CSS property.
Basic Syntax
CSS variables follow a simple syntax:
:root {
/* Define variables */
--color-primary: #3b82f6;
--spacing-md: 1rem;
--font-family: 'Inter', sans-serif;
}
.button {
/* Use variables */
background-color: var(--color-primary);
padding: var(--spacing-md);
font-family: var(--font-family);
}The -- prefix is required. Variable names are case-sensitive, so --color-primary and --Color-Primary are different variables.
Browser Support
CSS variables have excellent browser support, working in all modern browsers including Chrome, Firefox, Safari, and Edge. The only notable exception is Internet Explorer, which doesn't support them at all.
If you need IE support, you can use fallback values or a PostCSS plugin to compile variables to static values. However, for most projects in 2024+, this isn't a concern.
Naming Conventions
Good naming conventions make your variables predictable and easy to use. Here are common patterns:
Category-Based Naming
--color-primary: #3b82f6;
--color-secondary: #64748b;
--color-background: #ffffff;
--color-foreground: #0f172a;
--font-family: 'Inter', sans-serif;
--font-size-base: 1rem;
--font-weight-bold: 700;
--spacing-1: 0.25rem;
--spacing-2: 0.5rem;
--spacing-4: 1rem;Semantic Naming
--color-text: #0f172a;
--color-text-muted: #64748b;
--color-surface: #ffffff;
--color-surface-elevated: #f8fafc;
--button-bg: var(--color-primary);
--button-text: #ffffff;
--input-border: var(--color-border);The best approach often combines both: use category-based primitives and semantic tokens that reference them.
Cascading and Inheritance
CSS variables cascade and inherit like any other CSS property. This means you can:
- Define global variables on
:root - Override variables for specific components or sections
- Create scoped "themes" by redefining variables on containers
:root {
--color-primary: #3b82f6;
}
.dark-theme {
--color-primary: #60a5fa;
}
.special-section {
--color-primary: #8b5cf6;
}Any element inside .dark-theme will use the darker primary color without needing to change any other CSS.
Dynamic Updates with JavaScript
One of the most powerful features of CSS variables is that they can be updated at runtime with JavaScript:
// Set a variable
document.documentElement.style.setProperty('--color-primary', '#8b5cf6');
// Get a variable value
const primaryColor = getComputedStyle(document.documentElement)
.getPropertyValue('--color-primary');
// Remove a variable (reverts to inherited value)
document.documentElement.style.removeProperty('--color-primary');This enables powerful features like user-customizable themes, dynamic color schemes, and responsive design adjustments that would be impossible with preprocessor variables.
Fallback Values
The var() function accepts a fallback value that's used if the variable isn't defined:
.button {
/* Use #3b82f6 if --color-primary isn't defined */
background-color: var(--color-primary, #3b82f6);
/* Fallback can be another variable */
color: var(--button-text, var(--color-foreground));
}Performance Considerations
CSS variables are highly performant. The browser resolves them once during style calculation, not on every repaint. However, keep these tips in mind:
- Changing a variable triggers a repaint of all elements using it
- Define variables at the appropriate scope (don't use
:rootfor component-specific values) - Avoid deeply nested variable references when possible
CSS Variables vs Sass Variables
Sass variables and CSS variables serve different purposes:
| Feature | CSS Variables | Sass Variables |
|---|---|---|
| Runtime updates | Yes | No |
| JavaScript access | Yes | No |
| Media query responsive | Yes | No |
| Cascading/inheritance | Yes | No |
| Build step required | No | Yes |
| IE11 support | No | Yes |
Many projects use both: Sass for build-time calculations and mixins, CSS variables for runtime theming.
How PickCSS Uses CSS Variables
PickCSS generates a complete design system using CSS variables. When you export your design tokens, you get a theme.css file with 70+ variables organized by category:
:root {
/* Colors */
--color-primary: #3b82f6;
--color-primary-foreground: #ffffff;
--color-secondary: #64748b;
/* ... */
/* Typography */
--font-family: 'Inter', sans-serif;
--font-size-base: 1rem;
/* ... */
/* Spacing */
--spacing-1: 0.25rem;
--spacing-2: 0.5rem;
/* ... */
/* Border Radius */
--radius-sm: 0.25rem;
--radius-md: 0.5rem;
/* ... */
}These variables work in any project—React, Vue, plain HTML—and integrate seamlessly with Tailwind CSS and shadcn/ui.
Getting Started
Ready to build a design system with CSS variables? PickCSS generates production-ready tokens through simple binary choices—no design expertise required.
Create your design tokens and see CSS variables in action.