CSS Custom Properties (Variables): A Practical Guide
CSS custom properties (variables) are one of the most impactful modern CSS features. They make your stylesheets maintainable, themeable, and dynamic.
Basic Syntax
Define variables with -- prefix, use them with var():
:root {
--color-primary: #6366f1;
--radius: 12px;
--shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.card {
background: var(--color-primary);
border-radius: var(--radius);
box-shadow: var(--shadow);
}Fallback Values
Provide a default in case the variable isn't defined:
color: var(--text-color, #333);
padding: var(--spacing, 16px);This makes components portable — they work with or without the variable being set.
Dark Mode with Variables
The most practical use case — theme switching with zero JavaScript:
:root {
--bg: #ffffff;
--text: #111111;
--card: #f5f5f5;
--border: #e5e5e5;
--accent: #6366f1;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #0a0a0b;
--text: #e5e5e5;
--card: #18181b;
--border: #27272a;
--accent: #818cf8;
}
}
body { background: var(--bg); color: var(--text); }Change the variables, and every element using them updates automatically.
Scoped Variables
Variables cascade, so you can override them at any level:
:root { --accent: #6366f1; }
.danger-zone { --accent: #ef4444; }
.success-zone { --accent: #22c55e; }
.button { background: var(--accent); }A .button inside .danger-zone is red. Inside .success-zone, it's green. No extra classes needed.
Responsive Design with Variables
Change spacing or sizing at breakpoints:
:root {
--container-padding: 16px;
--font-size-heading: 1.5rem;
}
@media (min-width: 768px) {
:root {
--container-padding: 32px;
--font-size-heading: 2.5rem;
}
}Update variables in one place instead of overriding individual properties across your stylesheet.
Variables in Calculations
Combine with calc() for dynamic values:
:root { --base-spacing: 8px; }
.element {
padding: calc(var(--base-spacing) * 2); /* 16px */
margin-bottom: calc(var(--base-spacing) * 3); /* 24px */
gap: var(--base-spacing); /* 8px */
}This creates a consistent spacing system from a single variable.
Component Patterns
Build configurable components with internal variables:
.badge {
--badge-bg: var(--accent);
--badge-text: white;
--badge-size: 0.75rem;
background: var(--badge-bg);
color: var(--badge-text);
font-size: var(--badge-size);
padding: 2px 8px;
border-radius: 9999px;
}
.badge-outline {
--badge-bg: transparent;
--badge-text: var(--accent);
border: 1px solid var(--accent);
}JavaScript Integration
Read and write CSS variables from JavaScript:
// Read
getComputedStyle(document.documentElement).getPropertyValue('--accent');
// Write
document.documentElement.style.setProperty('--accent', '#ec4899');This is how JS-based theme switchers work — toggle a class or set variables directly.
CSS variables are the foundation of every tool on CSS Make. Try our Gradient Generator to see how custom properties can store and reuse gradient values, or the Glassmorphism Generator to create themeable glass effects.