A Practical Guide to CSS Variables (Custom Properties)
Share:
Free JavaScript Book!
Write powerful, clean and maintainable JavaScript.RRP $11.95
This post was updated in August 2018.
Preprocessors like Sass and Less certainly help to keep your CSS codebase organized and maintainable. Features like variables, mixins, loops, etc. — by adding dynamic capabilities to CSS coding — contribute to minimize repetition and speed up your development time.
In recent years, a few dynamic features have started to make their appearance as part of the CSS language itself. CSS variables — or “custom properties”, as they’re officially called — are already here and have great browser support, while CSS mixins are currently in the works.
In this article, you’ll find out how you can start integrating CSS variables into your CSS development workflow to make your stylesheets more maintainable and DRY (Don’t Repeat Yourself).
Let’s dive right in!
What are CSS Variables?
If you’ve used any programming language, you’re already familiar with the concept of a variable. Variables let you store and update values your program needs in order to work.
For instance, consider the following JavaScript snippet:
let number1 = 2;
let number2 = 3;
let total = number1 + number2;
console.log(total); // 5
number1 = 4;
total = number1 + number2;
console.log(total); // 7
number1
and number2
are two variables which store the number 2 and 3 respectively.
total
is also a variable which stores the sum of the number1
and number2
variables, in this case resulting in the value 5. You can dynamically change the value of these variables and use the updated value anywhere in your program. In the snippet above, I update the value of number1
to 4 and when I perform the addition again using the same variables, the result stored inside total
is no longer 5 but 7.
The beauty of variables is that they let you store your value in one place and update it on the fly for a number of various purposes. No need for you to add new entities with different values all over your program: all value updates happen using the same storage place, i.e., your variable.
CSS is mostly a declarative language, lacking in dynamic capabilities. You’d say that having variables in CSS would almost be a contradiction in terms. If front-end development were just about semantics, it would be. Fortunately, the languages of the Web are very much like living languages, which evolve and adapt according to the surrounding environment and the needs of their practitioners. CSS is no exception.
In short, variables have now become an exciting reality in the world of CSS, and as you’ll soon see for yourself, this awesome new technology is pretty straightforward to learn and use.
Are There Benefits to Using CSS Variables?
The benefits of using variables in CSS are not that much different from those of using variables in programming languages.
Here’s what the spec has to say about this:
[Using CSS variables] makes it easier to read large files, as seemingly-arbitrary values now have informative names, and makes editing such files much easier and less error-prone, as one only has to change the value once, in the custom property, and the change will propagate to all uses of that variable automatically.
In other words:
By naming your variables in ways that make sense to you in relation to your project, it’ll be easier for you to manage and maintain your code. For example, editing the primary color in your project will be much easier when what you need to change is one value for the --primary-color
CSS custom property, rather than change that value inside multiple CSS properties in various places.
What’s the Difference Between CSS Variables and Preprocessor Variables?
One way you might have been taking advantage of the flexibility of variables when styling websites is by using preprocessors like Sass and Less.
Preprocessors let you set variables and use them in functions, loops, mathematical operations, etc. Does this mean CSS variables are irrelevant?
Not quite, mainly because CSS variables are something different from preprocessor variables.
The differences spring from the fact that CSS variables are live CSS properties running in the browser, while preprocessor variables get compiled into regular CSS code, therefore the browser knows nothing about them.
What this means is that you can update CSS variables in a stylesheet document, inside inline style attributes and SVG presentational attributes, or choose to manipulate them on the fly using JavaScript. You can’t do any of this with preprocessor variables. This opens up a whole world of possibilities!
This is not to say that you need to choose between one or the other: nothing will stop you from taking advantage of the super powers of both CSS and preprocessor variables working together.
CSS Variables: The Syntax
Although in this article I use the term CSS variables for simplicity’s sake, the official spec refers to them as CSS custom properties for cascading variables. The CSS custom property part looks like this:
--my-cool-background: #73a4f4;
You prefix the custom property with two dashes and assign a value to it like you would with a regular CSS property. In the snippet above, I’ve assigned a color value to --my-cool-background
custom property.
The cascading variable part consists in applying your custom property using the var()
function, which looks like this:
var(--my-cool-background)
The custom property is scoped inside a CSS selector and the var()
part is used as value of a real CSS property:
:root {
--my-cool-background: #73a4f4;
}
/* The rest of the CSS file */
#foo {
background-color: var(--my-cool-background);
}
The snippet above scopes the --my-cool-background
custom property to the :root
pseudo-class, which makes its value available globally (it matches everything inside the <html>
element). Then it uses the var()
function to apply that value to the background-color
property of the container with ID of foo, which as a consequence will now have a nice light blue background.
That’s not all. You can use the same nice light blue color value to style other color properties of multiple HTML elements, e.g., color
, border-color
, etc., simply by retrieving the custom property’s value using var(--my-cool-background)
and applying it to the appropriate CSS property (of course, I recommend giving some thought to your naming convention for CSS variables before things get confusing):
p {
color: var(--my-cool-background);
}
See the Pen Basic Workings of CSS Variables by SitePoint (@SitePoint) on CodePen.
You can also set the value of a CSS variable with another CSS variable. For instance:
--top-color: orange;
--bottom-color: yellow;
--my-gradient: linear-gradient(var(--top-color), var(--bottom-color));
The snippet above creates the --my-gradient
variable and sets it to the value of both the --top-color
and --bottom-color
variables to create a gradient. Now, you can modify your gradient at any time anywhere you have decided to use it by just changing the values of your variables. No need to chase all the gradient instances all over your stylesheets.
Here’s a live CodePen demo.
See the Pen Setting Value of CSS Variable with Another CSS Variable by SitePoint (@SitePoint) on CodePen.
Finally, you can include one or more fallback value/s with your CSS variable. For example:
var(--main-color, #333);
In the snippet above, #333 is a fallback value. If fallbacks are not included, in case of invalid or unset custom properties, the inherited value will be applied instead.
CSS Variables Are Case Sensitive
Unlike regular CSS properties, CSS variables are case sensitive.
For instance, var(--foo)
and var(--FOO)
refer to two different custom properties, --foo
and --FOO
respectively.
CSS Variables Are Subject to the Cascade
Like regular CSS properties, CSS variables are inherited. For example, let’s define a custom property with the value blue:
:root {
--main-color: blue;
}
All elements inside the root <html>
element where you choose to apply the --main-color
variable, will inherit the value blue.
If you reassign a different value to your custom property inside another element, all children of this element will inherit the new value. For instance:
:root {
--main-color: blue;
}
.alert {
--main-color: red;
}
p {
color: var(--main-color);
}
<--! HTML -->
<html>
<head>
<!-- head code here -->
</head>
<body>
<div>
<p>blue paragraph.</p>
<div class="alert">
<p>red paragraph.</p>
</div>
</div>
</body>
</html>
The first paragraph in the markup above inherits its value from the global --main-color
variable, which makes it blue.
The paragraph inside the div element with the class of .alert
will be red because its color value is inherited from the locally scoped --main-color
variable, which has the value of red.
See the Pen Simple Example of CSS Variables Inheritance by SitePoint (@SitePoint) on CodePen.
Enough with the rules for now, let’s get coding!
How You Can Use CSS Variables with SVGs
CSS variables and SVGs work great together! You can use CSS variables to modify both style and presentational attributes inside inline SVGs.
Let’s say you’d like to have a different color for your SVG icons according to the parent container inside which they’re placed. You can scope your variables locally inside each parent container, set them to your desired color, and the icon inside each container will inherit the appropriate color from its parent.
Here are the relevant snippets:
/* inline SVG symbol for the icon */
<svg>
<symbol id="close-icon" viewbox="0 0 200 200">
<circle cx="96" cy="96" r="88" fill="none" stroke="var(--icon-color)" stroke-width="15" />
<text x="100" y="160" fill="var(--icon-color)" text-anchor="middle" style="font-size:250px;">x</text>
</symbol>
</svg>
/* first instance of the icon */
<svg>
<use xlink:href="#close-icon" />
</svg>
The markup above uses the <symbol>
tag, which enables you to create an invisible version of your SVG graphic. The code then instantiates a visible copy of the same graphic with the <use>
tag. This method lets you create any number of icons and customize them individually to your liking by simply referencing the <symbol>
element by its ID (#close-icon
). This is more convenient than repeating the same chunck of code over and over again to recreate the image. If you need to brush up on this technique, Massimo Cassandro offers a quick tutorial in his Build Your Own SVG Icons.
Notice the value of the stroke
property inside the circle element and of the fill
property inside the text element of the SVG symbol: they both apply a CSS variable, i.e., --icon-color
, which is defined in the :root
selector inside the CSS document, like so:
:root {
--icon-color: black;
}
This is what the icon looks like at this point:
If you now place an SVG icon inside different container elements and localize your variable inside each parent element’s selector with a different color value, you’ll have icons of different colors without having to add any more style rules. Cool!
To show this, let’s place an instance of the same icon inside the div with a class of .success
.
The HTML:
<div class="success">
<svg>
<use xlink:href="#close-icon" />
</svg>
</div>
Now, localize the --icon-color
variable by assigning the value green to it inside the .success
selector and check the result.
The CSS:
.success {
--icon-color: green;
}
The icon’s color is now green:
Have a look at the full demo below:
See the Pen Basic Use of SVG Icon and CSS Variables by SitePoint (@SitePoint) on CodePen.
How You Can Use CSS Variables with @keyframes
Animation
CSS variables can work with CSS animation, both on regular HTML elements and inline SVGs. Just remember to define the custom properties inside the selector that targets the element you want to animate, and refer to them with the var()
function inside the @keyframes
block.
For instance, to animate an <ellipse>
element with the class of .bubble
inside an SVG graphic, your CSS could look like this:
.bubble {
--direction-y: 30px;
--transparency: 0;
animation: bubbling 3s forwards infinite;
}
@keyframes bubbling {
0% {
transform: translatey(var(--direction-y));
opacity: var(--transparency);
}
40% {
opacity: calc(var(--transparency) + 0.2);
}
70% {
opacity: calc(var(--transparency) + 0.1);
}
100% {
opacity: var(--transparency);
}
}
Notice how you can perform calculations with the var()
function using CSS calc()
, which adds even more flexibility to your code.
The neat thing about using CSS variables in this case is that you can tweak your animations simply by modifying the variables’ values inside the appropriate selectors. No need to look for each of the properties inside all the @keyframes
directives.
Here’s the full CodePen demo for you to experiment with:
See the Pen Simple Animation with CSS Variables and SVG by SitePoint (@SitePoint) on CodePen.
How You Can Manipulate CSS Variables with JavaScript
One more super cool thing you can do is access CSS variables directly from your JavaScript code.
Let’s say you have a CSS variable called --left-pos
with a value of 100px
scoped to the .sidebar
class in your CSS document:
.sidebar {
--left-pos: 100px;
}
Getting the value of --left-pos
from your JavaScript code would look like this:
// cache the element you intend to target
const sidebarElement = document.querySelector('.sidebar');
// cache styles of sidebarElement inside cssStyles
const cssStyles = getComputedStyle(sidebarElement);
// retrieve the value of the --left-pos CSS variable
const cssVal = String(cssStyles.getPropertyValue('--left-pos')).trim();
// log cssVal to print the CSS
// variable's value to the console: 100px
console.log(cssVal);
To set a CSS variable with JavaScript, you can do something like this:
sidebarElement.style.setProperty('--left-pos', '200px');
The snippet above sets the value of the --left-pos
variable for the sidebar element to 200px
.
I find adding interactivity to a web page using CSS variables much more straightforward and maintainable than toggling a bunch of classes or rewriting entire CSS rules on the fly.
Have a look at the CodePen demo below, where you can interactively toggle a sidebar and change the blend mode property and the background color using only CSS variables and JavaScript:
See the Pen Blend Modes, CSS Variables and JavaScript by SitePoint (@SitePoint) on CodePen.
Browser Support for CSS Variables
Except for IE11 (which has no support for CSS variables), all major browsers have full support for CSS variables.
One way your code can cater for non-supporting browsers is to use the @supports
block with a dummy conditional query:
section {
color: gray;
}
@supports(--css: variables) {
section {
--my-color: blue;
color: var(--my-color, 'blue');
}
}
Given that @supports
works in IE/Edge, this will do the trick. If you also take advantage of fallback values inside the var()
function, your code will be even more foolproof and degrade gracefully in less capable browsers.
As a result, in Chrome and other supporting browsers, the text inside the <section>
element will be blue:
IE11, which has no support for CSS variables, renders the page with gray-colored text:
Check out the live demo:
See the Pen @supports with CSS Variables by SitePoint (@SitePoint) on CodePen.
One downside to this approach is that if you use CSS variables a lot and non-supporting browsers are a priority in your current project, then the code could get somewhat complicated and a bit of a nightmare to maintain.
In this case, you could opt for PostCSS with cssnext, which lets you write cutting-edge CSS code and make it compatible with non supporting browsers (a bit like transpilers do for JavaScript). If you’re curious about PostCSS, SitePoint Premium makes available an excellent video course on this topic to all its members.
Resources
To learn more about the ins and outs of CSS variables, including browser support workarounds and interesting use cases, check out the resources below:
- CSS Custom Properties for Cascading Variables Module Level 1 — W3C Spec
- Using CSS variables — MDN
- Lea Verou’s Talk on CSS Variables for CSSConf Asia 2016 (video)
- What is the difference between CSS variables and preprocessor variables? — Chris Coyier (CSS-Tricks)
- It’s Time To Start Using CSS Custom Properties — Serg Hospodarets (Smashing Magazine)
- Locally Scoped CSS Variables: What, How, and Why — Una Kravets
- Pragmatic, Practical, and Progressive Theming with Custom Properties — Harry Roberts (CSS Wizardry)
- Customizable SVG Icons with CSS Variables — Amelia Bellamy-Royds (CodePen).
Fun Demos
- Animation with CSS Variables — Wes Bos
- Update CSS Variables with JS — Wes Bos
- Simple responsive grid with CSS variables — Chris Coyier
- Slack Theming with CSS Custom Properties — Stephanie
- Ana Tudor’s CSS variables demos on CodePen.
What are you waiting for? Give CSS variables a try and let me know what you think in the comments!
Maria Antonietta Perna is a teacher and technical writer. She enjoys tinkering with cool CSS standards and is curious about teaching approaches to front-end code. When not coding or writing for the web, she enjoys reading philosophy books, taking long walks, and appreciating good food.
New books out now!
Get practical advice to start your career in programming!
Master complex transitions, transformations and animations in CSS!
Latest Remote Jobs




