Hey there fellow coder!
CSS variables are one of those features that, once you start using them, you‘ll wonder how you ever coded without them. As a professional web developer and designer myself, I definitely think CSS variables deserve a spot in your frontend toolkit.
In this comprehensive guide, I‘ll explain everything you need to know to start using CSS variables in your projects. You‘ll learn:
- What exactly CSS variables are and why they‘re so useful
- How to declare and use CSS variables with some handy examples
- Clever ways to use variables that you may not have considered
- How CSS variables work under the hood
- Browser compatibility considerations
- How variables open new possibilities like dynamic styling
And by the end, you‘ll have the confidence to start streamlining your stylesheets with variables like a pro. Let‘s get started!
What Are CSS Variables?
CSS variables, officially called "custom properties" in the spec, provide a way to store reusable values in CSS.
Some examples of values you might want to store in variables include:
- Colors – Like primary brand color, secondary color, etc.
- Font sizes – For text, headings, etc.
- Spacing values – For margins, padding, etc.
- Breakpoints – For media queries
- Box shadows
- Transition speeds
The syntax looks like this:
selector {
--variable-name: value;
}
So you declare a variable by starting with two dashes (--) followed by a name you define, like --brand-color, then a colon, and finally the value you want it to store.
You can then use that variable later with the var() function:
element {
/* Reference the --brand-color variable */
background: var(--brand-color);
}
This makes the value reusable across your stylesheet.
Why Are Variables Useful?
There are a few key reasons why CSS variables are worth using:
Easier maintenance
Updating a variable value in one place propagates the change everywhere it‘s used. This can save you a huge amount of time compared to changing values manually throughout a stylesheet.
Improved readability
Variables often make the CSS more understandable for humans by using meaningful names like --primary-color rather than hex codes.
Consistency
You can store values like colors and font sizes to reuse them consistently across elements. No more guessing hex codes!
Responsive design
Variables make media queries more concise by storing breakpoints as named values.
Dynamic styling
CSS variables can be updated dynamically through JavaScript, allowing flexible theming and styling.
Professional developers like you and me know that writing maintainable and readable CSS is crucial for any large or long-term project. Variables help us accomplish that.
Later in this guide I‘ll also cover some more advanced uses of variables that you may not have considered. But first, let‘s look at how to start declaring and using them effectively.
How to Declare and Use CSS Variables
The basic syntax for declaring a variable looks like this:
selector {
--variable-name: value;
}
Then you can access that variable through the CSS using var():
element {
property: var(--variable-name);
}
Let‘s look at some examples.
First I‘ll declare my brand colors on the root element:
:root {
--brand-primary: #6743FF;
--brand-secondary: #42E3C9;
}
This makes them globally available to use anywhere in the stylesheet.
Now I can reference them in my selectors:
header {
background: var(--brand-primary);
}
a {
color: var(--brand-secondary);
}
And here are some more advanced examples:
:root {
--container-width: 1200px;
--gutter: 20px;
}
.container {
width: var(--container-width);
margin: 0 auto;
}
section {
padding: var(--gutter);
}
This defines some layout-related variables at the global scope. We reuse them to size a container and add consistent padding.
Or say you have a media query breakpoint:
:root {
--small-viewport: 600px;
}
@media (max-width: var(--small-viewport)) {
/* responsive styles */
}
Storing the breakpoint in a variable avoids repetition.
As you can see, the possibilities are endless!
Local vs. Global Scope
An important point about variables is that they can have local or global scope:
Global variables are declared on the :root element and can be accessed anywhere in your CSS. This is how we made the brand colors and layout variables globally available in the examples above.
Local variables are scoped to a particular selector where they are declared. For example:
.callout {
--border-radius: 5px;
}
.callout {
border-radius: var(--border-radius);
}
Here --border-radius is local to .callout and can‘t be accessed outside of that.
As a best practice, define global variables in :root and local variables on specific selectors when you can.
Default and Fallback Values
When using variables, sometimes you‘ll want a default or fallback value in case the variable isn‘t defined.
For example, we can set a default value while declaring the variable:
:root {
--brand-color: #6743FF;
}
a {
color: var(--heading-color, --brand-color);
}
Here if --heading-color doesn‘t exist, it will fall back to --brand-color.
Or in the var() function:
a {
color: var(--color, blue);
}
Now the text color will be blue by default if --color isn‘t defined.
This provides flexibility in case some variables aren‘t always available.
When to Use Variables vs. Hardcoded Values
At this point you may be wondering – should I use variables for everything in my CSS?
The answer is – it depends! Here are some guidelines on when to use variables vs. just hardcoded values:
Use variables when:
- A value is reused multiple times
- A value is likely to change across a project
- You want to store a global/theme-level value
- You want to make a value dynamic
Hardcoded values are OK when:
- It‘s a one-off value unlikely to be reused
- The value is very unlikely to ever change
- It makes the code confusing to abstract (too many variables)
In general, use your best judgment based on the situation. Variables for everything can get messy but they can really help manage complex or reusable values.
Now let‘s look at how pro developers can take variables to the next level…
Advanced Uses of CSS Variables
While variables at first may seem only useful for storing simple values like colors, they can actually power some really advanced CSS techniques.
Dynamic Variables with JavaScript
A game-changing aspect of CSS variables is that they can be dynamically changed with JavaScript.
Let‘s see an example of changing a variable on click:
// JS
const button = document.querySelector(‘button‘);
button.addEventListener(‘click‘, () => {
button.style.setProperty(‘--color‘, ‘rebeccapurple‘);
});
/* CSS */
button {
background: var(--color, yellow);
}
When clicked, the --color variable will change to rebeccapurple and update the <button> background.
You can also update variables based on user input like text fields or color pickers. This enables dynamic theming and styling without reloading the page.
Media Query Variables
CSS variables open some cool possibilities for responsive design.
We can store entire breakpoint values as variables for better readability:
:root {
--breakpoint-medium: 500px;
}
@media (max-width: var(--breakpoint-medium)) {
/* responsive code */
}
Calculating Values
The calc() function allows you to do math operations with variables:
:root {
--base-value: 8px;
}
div {
/* Double the base value */
padding: calc(2 * var(--base-value));
}
This dynamically calculates values based on other variables.
Theming
CSS variables enable dynamic theming by simply changing which variable values are applied:
/* Light theme */
:root {
--text-color: #222;
--bg-color: #fff;
}
/* Dark theme */
.dark-theme {
--text-color: #ddd;
--bg-color: #333;
}
Here we define two separate themes using variables. We could toggle a dark-theme class with JavaScript to implement this.
Component Variables
For large projects like design systems, you can store component-specific variables:
/* Button component */
.btn {
--btn-bg-color: #6743FF;
--btn-text-color: #fff;
}
.btn {
background: var(--btn-bg-color);
color: var(--btn-text-color);
}
This is a more object-oriented approach to styling.
There are endless creative possibilities! CSS variables enable patterns like dynamic theming, responsive design, calculated values, and component-based architectures.
Browser Compatibility
CSS variables have excellent browser support, but there are a few exceptions to be aware of.
| Browser | Compatibility |
|---|---|
| Chrome | Full support as of version 49+ |
| Firefox | Full support as of version 31+ |
| Safari | Full support as of version 10+ |
| Edge | Full support as of version 15+ |
| IE11 | No support |
So the main caveat is lack of support in IE11 and legacy browsers. But we have some options to deal with that:
-
Use a CSS variable polyfill which adds support in old browsers. Popular options include postcss-custom-properties and css-vars-ponyfill.
-
Provide fallback values using techniques mentioned earlier like default values.
-
Use feature detection to only apply CSS variable-driven styles in supported browsers. For example:
// Feature detection
if (window.CSS && CSS.supports(‘color‘, ‘var(--fake-var)‘)) {
// Variables supported!
} else {
// No support
}
So make sure to check for compatibility issues, but in general you can safely use CSS variables today.
Now let‘s get into the technical details of how they actually work under the hood…
How CSS Variables Work Internally
On the CSS engine level, variables introduce a new concept called "custom properties" that function differently than standard properties.
Some key behavioral differences:
-
Variables are resolved at computed value time rather than specified value time. The W3C spec defines what this means in detail, but in short, variables are evaluated later in the process than regular properties.
-
Variables don‘t inherit a value from their parent element. The variable must be declared on each selector that needs to use it.
-
Multiple declarations of the same variable name overwrite each other rather than cascade.
-
Variables can only be accessed through the
var()function rather than referenced directly.
These unique behaviors allow variables to function as dynamic, contextual values rather than static inheritied ones.
Browsers had to implement custom properties from scratch to make variables work. Unlike a new CSS value keyword which existing properties can automatically accept, variables fundamentally change the property evaluation flow.
This is implemented something like:
For each property on an element:
If property value contains var():
Resolve variables and evaluate resulting value
Else:
Evaluate property value normally
Of course, browser engines do a ton more under the hood to optimize this process. But that‘s the general idea!
When to Start Using CSS Variables
If you‘re just learning about CSS variables for the first time, here are some good ways to start using them in your code:
Brand colors – Rather than hardcoding color values, store them in variables like --brand-primary and --brand-secondary.
Font sizes – Set up some typography variables for base size, heading sizes, etc.
Breakpoints – Use variables for your responsive breakpoint values to reduce "magic numbers".
Box shadows – Reuse shadows across elements with a --shadow variable.
Spacing – Standardize padding and margin sizes based on spacing variables like --gap.
These types of reusable values are generally the easiest places to apply variables at first.
Over time, you can start exploring more advanced patterns like calculated values, dynamic variables, theming, etc. But start with the basics and go from there.
The key is incrementally building the variable habit. Even using them for brand colors alone can clean up your stylesheets.
Putting Variables to Work
Hopefully by now you have a good understanding of how to use CSS variables and are itching to put them into practice!
Here‘s a quick recap of the key benefits:
- Store reusable values like colors, font-sizes, and breakpoints
- Improve code maintenance, readability, and consistency
- Allow dynamic value updates through JavaScript
- Better organize UI components and themes
- Do math operations by calculating values
To get started:
-
Declare some global variables on
:root– colors, fonts, etc. -
Reference them in selectors with
var()instead of hardcoded values. -
Use local variables for component-specific values.
-
Take advantage of fallbacks and defaults to support older browsers.
-
Explore advanced patterns like theming and calculated values.
Code intelligently using CSS variables and it will pay dividends in developer experience. I‘m confident you‘ll be able to use them like a pro in your projects in no time!
Let me know if you have any other questions. And happy styling my friend!