How to Declare Variables in CSS - CSS Custom Properties Complete Guide
If you have ever updated a colour in your CSS and then spent the next ten minutes hunting down every other place you used the same colour to change it too โ CSS variables are about to become your new favourite feature. They let you store values in one place and reuse them everywhere, making your stylesheets dramatically easier to maintain, theme, and update.
In this guide we will cover everything about CSS variables โ what they are, how to declare them, how scope works, fallback values, dynamic updates with JavaScript, and how to use them to build a proper dark mode toggle. All with working examples you can use immediately.
What Are CSS Variables?
CSS variables โ officially called CSS Custom Properties
โ are entities you define yourself and reuse throughout a stylesheet.
Think of them the same way you think of variables in JavaScript or PHP.
Instead of writing #3b82f6 fifty times across your
stylesheet, you define it once as --primary-color: #3b82f6
and reference it everywhere with var(--primary-color).
Change the value in one place and it updates everywhere automatically. That is the core benefit โ and it goes far beyond just colours.
How to Declare a CSS Variable
CSS variables always start with two dashes (--) followed
by the variable name. They are case-sensitive and can store any CSS
value โ colours, sizes, fonts, spacing, shadows, anything.
/* Syntax */
--variable-name: value;
/* Examples */
--primary-color: #3b82f6;
--secondary-color: #facc15;
--font-size-base: 16px;
--border-radius: 8px;
--spacing-md: 1.5rem;
--font-family: 'Inter', sans-serif;
--shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
To use a CSS variable, wrap it in var():
/* Using a variable */
button {
background-color: var(--primary-color);
border-radius: var(--border-radius);
font-family: var(--font-family);
box-shadow: var(--shadow);
}
Global Variables โ Using :root
The most common place to declare CSS variables is inside the
:root selector. :root targets the highest
level element in the document โ the <html> tag โ
which means variables declared here are available everywhere in your
stylesheet. Think of it as your global variable scope.
/* Declare all your design tokens in :root */
:root {
/* Colours */
--color-primary: #3b82f6;
--color-secondary: #facc15;
--color-success: #22c55e;
--color-danger: #ef4444;
--color-background: #111827;
--color-text: #f9fafb;
--color-muted: #6b7280;
/* Typography */
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.25rem;
--font-size-xl: 1.5rem;
--font-weight-normal: 400;
--font-weight-bold: 700;
/* Spacing */
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 2rem;
--spacing-xl: 4rem;
/* Borders */
--border-radius-sm: 4px;
--border-radius-md: 8px;
--border-radius-lg: 16px;
--border-radius-full: 50%;
/* Shadows */
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.12);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.15);
--shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.2);
}
/* Now use them anywhere in your stylesheet */
body {
background-color: var(--color-background);
color: var(--color-text);
font-size: var(--font-size-base);
}
h1 {
font-size: var(--font-size-xl);
font-weight: var(--font-weight-bold);
color: var(--color-primary);
}
.card {
background: var(--color-background);
border-radius: var(--border-radius-md);
padding: var(--spacing-lg);
box-shadow: var(--shadow-md);
}
.btn-primary {
background: var(--color-primary);
border-radius: var(--border-radius-sm);
padding: var(--spacing-sm) var(--spacing-md);
color: #fff;
}
Live Demo โ CSS Variables in action
All three buttons use the same CSS class โ only the variable values change
Local Variables โ Scoped to a Specific Element
CSS variables do not have to be global. You can declare them inside any selector โ they will only be available to that element and its children. This is called local scope and is very useful for component-specific styling.
/* Global default */
:root {
--button-color: #3b82f6;
}
/* Override locally for a specific component */
.danger-section {
--button-color: #ef4444; /* only applies inside .danger-section */
}
.btn {
background: var(--button-color); /* uses local value if available, global otherwise */
}
/* Result:
Normal .btn โ blue (#3b82f6)
Inside .danger-section .btn โ red (#ef4444)
*/
This is a powerful pattern for component-based design โ each component can define its own local variables that override the global defaults without affecting anything else on the page.
Fallback Values
The var() function accepts an optional second argument โ
a fallback value that is used if the variable is not defined:
/* Syntax: var(--variable-name, fallback-value) */
.card {
/* Uses --card-background if defined, otherwise uses #1f2937 */
background: var(--card-background, #1f2937);
/* Uses --border-radius if defined, otherwise falls back to 8px */
border-radius: var(--border-radius, 8px);
/* Fallback can also be another variable */
color: var(--card-text-color, var(--color-text, #ffffff));
}
Fallbacks are useful when building reusable components or design systems where some variables might not always be set. They also make your CSS more defensive โ if someone forgets to define a variable, the fallback keeps things from breaking.
Changing CSS Variables With JavaScript
This is where CSS variables become truly powerful. You can read and write CSS variable values from JavaScript in real time โ which means you can dynamically change your entire design based on user input, API data, or any runtime condition.
// Read a CSS variable value
const root = document.documentElement;
const value = getComputedStyle(root).getPropertyValue('--primary-color');
console.log(value); // "#3b82f6"
// Set a CSS variable value โ updates instantly everywhere it is used
root.style.setProperty('--primary-color', '#22c55e');
// Remove a CSS variable
root.style.removeProperty('--primary-color');
// Change a variable on a specific element (not root)
const card = document.querySelector('.card');
card.style.setProperty('--card-background', '#1e3a5f');
When you call setProperty(), every element using that
variable updates instantly across the entire page โ no class toggling,
no style recalculation, just one line changing one value.
Building Dark Mode With CSS Variables
CSS variables are the cleanest way to implement dark mode. Define two sets of values โ one for light, one for dark โ and toggle between them with a single class or the OS preference:
/* Light mode โ default */
:root {
--bg: #ffffff;
--bg-secondary: #f3f4f6;
--text: #111827;
--text-muted: #6b7280;
--border: #e5e7eb;
--primary: #3b82f6;
}
/* Dark mode โ activated by class on html element */
:root.dark {
--bg: #111827;
--bg-secondary: #1f2937;
--text: #f9fafb;
--text-muted: #9ca3af;
--border: #374151;
--primary: #60a5fa;
}
/* System preference โ auto dark mode */
@media (prefers-color-scheme: dark) {
:root {
--bg: #111827;
--bg-secondary: #1f2937;
--text: #f9fafb;
--text-muted: #9ca3af;
--border: #374151;
--primary: #60a5fa;
}
}
/* All your components use variables โ no changes needed for dark mode */
body { background: var(--bg); color: var(--text); }
.card { background: var(--bg-secondary); border: 1px solid var(--border); }
.text-muted { color: var(--text-muted); }
.btn { background: var(--primary); }
Toggle dark mode with one line of JavaScript:
// Toggle dark mode
function toggleDarkMode() {
document.documentElement.classList.toggle('dark');
}
// Or read system preference
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (prefersDark) {
document.documentElement.classList.add('dark');
}
CSS Variables vs Sass/SCSS Variables
If you have used Sass before you are familiar with variables like
$primary-color: #3b82f6. CSS variables and Sass variables
look similar but work very differently:
| CSS Variables | Sass Variables | |
|---|---|---|
| Syntax | --color: #fff |
$color: #fff |
| Lives in | Browser โ runtime | Build step โ compiled away |
| JavaScript access | โ Yes โ read and write | โ No โ gone after compile |
| Dynamic update | โ Yes โ instantly | โ No |
| Scoping | โ Any selector | File/module level |
| Requires build tool | โ Pure CSS | โ Sass compiler needed |
| Browser support | All modern browsers | Any (compiled to CSS) |
The key takeaway: Sass variables are processed at build time and disappear from the final CSS. CSS variables exist at runtime in the browser โ which is why JavaScript can read and update them, and why they are the only way to do things like dark mode toggling and dynamic theming without JavaScript manipulating classes.
Common Mistakes to Avoid
1. Forgetting the two dashes
/* โ Wrong โ single dash is not a CSS variable */
:root {
-primary-color: #3b82f6;
}
/* โ
Correct โ always two dashes */
:root {
--primary-color: #3b82f6;
}
2. Using var() outside a CSS property value
/* โ Wrong โ cannot use var() as a selector or property name */
.var(--component-class) { color: red; }
var(--property-name): blue;
/* โ
Correct โ var() only works as a property VALUE */
.card { background: var(--card-bg); }
3. Expecting var() to work in media queries
/* โ Wrong โ CSS variables do not work inside @media queries */
:root { --breakpoint-md: 768px; }
@media (min-width: var(--breakpoint-md)) { ... } /* does NOT work */
/* โ
Use the actual value in media queries */
@media (min-width: 768px) { ... }
/* Or use CSS env() for some browser-defined values */
4. Not providing fallbacks in reusable components
/* โ Risky โ if --card-bg is not defined, background is undefined */
.card { background: var(--card-bg); }
/* โ
Safe โ fallback ensures component always renders correctly */
.card { background: var(--card-bg, #1f2937); }
Browser Support
CSS variables are supported in all modern browsers โ Chrome, Firefox, Safari, Edge, and Opera. Global browser support is above 96% as of 2026. You do not need any polyfill or build tool to use them. If you need to support Internet Explorer 11 (which you almost certainly do not anymore), that is the one exception โ IE11 does not support CSS custom properties.
Final Thought
CSS variables are one of those features that feel like a small
convenience when you first learn them and then become absolutely
indispensable once you are used to them. Maintaining a large stylesheet
without them is painful โ changing a brand colour means a global find
and replace across multiple files. With CSS variables it is one line
change in :root.
Start with a simple :root block that defines your colours,
font sizes, and spacing. Use those variables throughout your stylesheet.
Within a week it will feel natural โ and the next time your client asks
to change the primary colour from blue to green, you will smile instead
of groan.
Have a CSS question or building something specific you need help with? Drop us a message on our contact page โ happy to help.
๐ You Might Also Like
- โ Best Google AdSense Alternative 2026 - Monetag Review for Publishers miscellaneous
- โ How to Start Freelancing as a Web Developer in 2026 (Complete Beginner's Guide) miscellaneous
- โ HTTP QUERY Method (RFC 10008) โ The New HTTP Method Every Developer Should Know miscellaneous
- โ JavaScript Array Methods Cheat Sheet โ Complete Guide with Example javascript
- โ MyLync โ Best Free Linktree Alternative for Developers, Creators & Businesses miscellaneous