When I first thought about CSS variables, I didn’t really see how they would be useful. I was just thinking about variables in terms of reusing values. So, define a color in a variable, reuse it in a few spots. That alone is kind of helpful…if I want to change the color, just change it in the variable and it trickles down to all of the spots I used it. We already have that though, within any of the CSS preprocessors. And, I feel like the job of resolving a reusable variable makes more sense to do at build time, than in the browser.
But, with the kind of recent addition of CSS variables in Firefox, I’ve given them a second thought. The real value of CSS variables comes from their ability to enable configuration and customization of reusable components. And, with web components slowly, but surely coming, this is going to be an even more important concept.
If you haven’t seen the syntax of CSS variables, here are the basics. A CSS variables is much the same as a variable in any other programming language. You declare them with a name and a value, then can use them throughout your CSS.
The syntax to declare a new CSS variable is similar to anything in CSS. It is a
name: value pair. And it must be declared inside a ruleset for a selector. To globally declare the variable, it can just be done on the
:root. The specific syntax is:
To reference a variable, you use the
var() notation passing in the name of the variable.
The cool part
CSS variables are scoped via the cascade and specificity just like any other CSS rule. That means we can use the same variable name, but set it to different values for different selectors.
So, a simple example…we want the link color as a default to be blue, but if it has a class of
link-alt to be red, if it is inside of the the
.sidebar of the site to be green, and on really large screens to be yellow. Here’s how we could set that up:
The real value, I think, is in the
.sidebar case. Traditionally, we would have either had to create a new class for the link to have a green color (like we did with
.link-alt) or we would have had to make use of a longer selector (
.sidebar a). For a simple link, there’s not any huge efficiency gain here, but let’s look at a bigger example.
A reusable component
For this example, let’s just say we have a panel component that we might want to drop in different places on our website. Some simple markup:
For the default styling we’re going with a gray and white theme, with some standard padding.
Now, if we want to drop the panel into the footer of the site, which may be a different color and might have a little less room (so we want to decrease the padding), we’re going to have to make some changes. Without variables, we’d need to create modifiers for the
.panel-header and the
.panel-body. It would look something like:
So our CSS has almost doubled in size and we now need to modify our HTML with the new classnames. So that’s not ideal. The other way to do it without variables, is to prefix all of our selectors with the the footer.
Again the CSS has dramatically grown, but at least we don’t have to change our HTML…it’s just a copy and paste. But the specificity of all of our selectors has grown too. That’s not necessarily a big problem, but I like to keep everything at the class/attribute specificity level for simplicity and to let the cascade do its thing.
So here is where variables can really help us out. First let’s make some of those properties configurable with variables.
Now we can just update those variables for the footer.
And that’s it. That’s all the extra CSS needed and no changes are needed to the HTML…just drop it in the footer.
The spec for CSS Variables has some features that have not been implemented in any of the browser (as far as I can tell at least). The one that I think is most exciting is a second argument that can be passed into
var that defines a fallback value if the variable has not been set. (If you’re familar with Sass, this is very similar to defining a variable with
In this case, if
var-my-color hasn’t been defined anywhere in scope, then the color of the
h1 will fallback to a nice bright red,
#f00. The fallback argument makes defining default values much simpler. You will no longer have to load up the
:root with all of the defaults…they can be defined in place.
Now what we need is for much better browser support. Chrome has had CSS Variables behind the “Experimental Web Platform features” flag for a while and Firefox now has them behind the
layout.css.variables.enabled preference. Hopefully soon they’ll both be available by default and more browser will add support too.
Updated [5/20/2014] - The spec has changed! Instead of the
var-* syntax, it is now
--* for custom properties. You still use them using the
var() syntax however.