Why CSS Custom Properties (a.k.a. CSS Variables) are Awesome

CSS custom properties (or CSS variables, as they’ll likely be referred to by most people) have gained a lot of attention lately with the releases of Chrome 49 and Firefox 43, both of which support them without the need for a prefix. Rob Dodson from Google recently wrote an excellent article on them. Like many people, my instant reaction was something like, why would I need in-browser CSS variables if I use Sass? But after fiddling with them for a few days I now understand that their usefulness extends beyond what Sass (or any other preprocessor) is capable of.

How CSS Variables Work

CSS variables work much the same as the variables you’re using in other languages. You make up a name, assign it a value, and then refer to that name later in your code. Here’s how you do it in CSS:

:root{
  --myColor: #bada55;	
}
.my-element{
  background-color: var(--myColor);
}

This will set the value of background-color to #bada55. Some important things to note:

  • The variable name begins with two dashes. This is mandatory. Also, the name is case sensitive. --myColor is different from --mycolor.
  • The variable is set on a selector, in this case the pseudo class :root. But it can be any element that’s a parent of the elements that will use the variable. html would work pretty well too if you want your variable global.
  • The way you call the variable is with the var() function.

Stop Thinking About Sass

I know you still are. Let me show you why you need to start looking at CSS variables as a whole new beast. Think about this example:

*{
  width: var(--myWidth);	
}
#element{
  --myWidth: 32px;	
}
.widget{
  --myWidth: 25%;	
}
section{
  --myWidth: 50%
}

Every element will have its width set to --myWidth (via the star selector). But the value of --myWidth will change on a per-element basis if the element’s specificity is great enough. In other words, CSS variables follow the cascade, which is something Sass variables don’t even attempt to do.

Here’s another trick CSS variables have up their sleeve:

:root{
  --myWidth: 75%;	
}
.main-content{
  width: var(--myWidth);	
}
@media (max-width: 700px){
  :root{
    --myWidth: 100%;
  }	
}

Yep, you can declare variables inside of media queries. We’re through the looking glass here people…

More Cool Stuff

Variables Within Variables

CSS variables can get their value from other variables:

body{
  --accentColor: #666;	
  --logoColor: var(--accentColor);
}

Fallback Values

The var() function allows you to set not only the variable, but any fallback values to use in case the variable is invalid.

:root{
  --myFont: 'Helvetica';	
}
p{
  font-family: var(--myFont, arial, sans-serif);
}

Using calc()

You can use your variables inside of the calc() function, like this:

html{
  --spacer: 30;	
}
.widget p{
  margin-bottom: calc(var(--spacer + 10px));	
}

CSS Variables in JavaScript

Perhaps what separates CSS variables from Sass variables more than anything else is the ability to work with them inside JavaScript. You can use the JavaScript methods getPropertyValue() and setProperty() to retrieve or set a CSS variable, respectively. Rob’s article has some excellent examples.

Browser Support

This is always the bummer part. But fortunately things aren’t too bad for CSS variables. Chrome and Firefox are a go! And Safari 9.1 and iOS Safari 9.3 will also introduce support.

Internet Explorer/Edge
Not Supported
Firefox
43+
Chrome
49+ (48 behind flag)
Safari
9.1+
Opera
Not Supported
iOS Safari
9.3+
Chrome for Android
Not Supported

Conclusion

I hope you can see how incredibly useful CSS variables are. I also hope you see that CSS variables and Sass variables are definitely not in some sort of battle for dominance. Their functionality barely overlaps, and you’ll likely find that they fit nicely side-by-side in your web toolbox. Start using them today. If you need to support IE/Edge you’ll need to use caution, but it shouldn’t be too tricky to concoct a workable fallback.