CSS Variables or Custom Properties
21 Mar 2018
CSS variables
or
Custom Properties
Variables in CSS. At first glance, this might not seem like a big deal as variables declared in SASS/SCSS have already been around for quite some time. Taking a closer look at the differences between CSS and SCSS variables, one begins to realize the power of CSS variables.
CSS variables vs SCSS variables
SCSS variables are static. Once they are processed and compiled, they are written in the CSS file and cannot be changed (except for by adding another style tag or CSS file that overwrites the first CSS file). The output of an SCSS variable is, in the end, a CSS declaration. To change the output of the variable, the SCSS file has to be processed and compiled yet again in a file build process.
CSS variables, on the other hand, are dynamic in that they can be changed and updated depending on context. CSS variables are affected by the cascade, can be targeted via CSS selectors and can be changed within media queries. A CSS variable can, therefore, depending on different circumstances hold multiple different values at the same time.
Just remember that the CSS variables are meant to be used for storing (and declaring) CSS properties, not just any data. For example, it is not possible to use them for declaring media query breakpoints. But don’t worry, using them inside of media queries is totally ok.
Support
Ok, so CSS properties are powerful, but what about browser support? caniuse.com shows that the most popular modern browsers including Edge (v16 and upwards) support the feature.
So basically CSS properties are ok to use unless you need to support Internet Explorer. In that case, you will need to write fallbacks.
Warning
There is apparently a bug in Firefox concerning variables used together with calc() which seems to be unsolved.
Fallbacks
Adding fallbacks for non-supporting browsers can be done by declaring a fallback value that an older browser can process instead of the new and fancy variable.
.btn{
color: green;
--btn-color: green;
color: var(--btn-color);
}
It is also possible to use the @supports
declaration because browsers that support @supports
also supports CSS properties. The declaration would look like this:
@supports(--css: variables) {
/*code for browsers that support CSS Custom Properties*/
}
Where the variable name and value could be anything that is an accepted CSS property declaration.
I currently do not know of any working js polyfill that can be added to make CSS properties work everywhere (automagically).
Use Cases
Templating
The possibility to update a value once, and have it take effect in multiple places makes it easier both to keep code DRY and to maintain the codebase.
It is also possible to declare variables just on certain elements, and not globally on the :root
. CSS variables are scoped within their respective set of {}
, unless they are declared on the :root
. If declared on the root (the HTML element), they are globally available.
Typical use cases are templating or theming. Example with three buttons with different color themes:
.btn{
background-color: white;
padding: 0.5em 1em;
border: 0.125em solid black;
color: black;
}
.btn-red{
border-color: red;
color: red;
}
.btn-blue{
border-color: blue;
color: blue;
}
Instead of repeating the border-color
and color
for .btn-blue
and .btn-red
, using CSS variables the code can become:
:root{
--btn-color: black;
}
.btn{
background-color: white;
padding: 0.5em 1em;
border: 0.125em solid var(--btn-color);
color: var(--btn-color);
}
.btn-red{
--btn-color: red;
}
.btn-blue{
--btn-color: blue;
}
If you wanted to keep the variable away from the global scope, you could do so by declaring it on the .btn
:
.btn{
--btn-color: black;
color: var(--btn-color);
}
It is also possible to add fallback values, which is really useful. Fallbacks are declared like so: var(--btn-color, green)
. Which when added to the .btn
class would make the color for elements with only the .btn
class fall back to green.
.btn{
background-color: white;
padding: 0.5em 1em;
border: 0.125em solid var(--btn-color, green);
color: var(--btn-color, green);
}
Updating Styles at Certain Breakpoints
Another way CSS properties can help making style changes easier and more maintainable is using them with media queries.
Instead of making multiple changes to the CSS, it is possible to update just one variable that will take effect everywhere it is being used:
:root{
--regular-fontsize: 1em;
}
p{
font-size: var(--regular-fontsize);
margin: var(--regular-fontsize) 0;
}
/*imagine the var --regular-fontsize is used throughout the website*/
@media screen and (min-width: 30em) {
/*it can then be conveniently changed everywhere at once by updating the value inside a media query.*/
:root{
--regular-fontsize: 1.25em;
}
}
Using calc to Supercharge CSS Properties
It is when CSS variables are used in calc expressions perhaps the most impressive results are produced. In the blog post “Responsive Typography with CSS Custom Properties (CSS Variables)”, I’m doing a deep dive in how to achieve true responsive typography (that continuously dynamically scales with window width) using calc()
together with CSS variables.
CSS variables can be declared unitless. Add whatever unit you need by multiplying it with the variable in a calc()
expression. Leveraging this, CSS variables and calc()
allow us to write more dynamic code – just using CSS:
:root{
--modular-scale: 1.125;
}
p{
font-size: calc(var(--modular-scale) * 1em);
}
h6{
font-size: calc(var(--modular-scale) * var(--modular-scale)* 1em);
}
@media screen and (min-width: 60em) {
:root{
--modular-scale:1.3333;
}
}
With JS and Dynamic Inputs
If what can be achieved with CSS variables alone is amazing, adding JS to the receipt further expands the horizon. By attaching some sort of user input to CSS variables that updates or changes them, some really fun effects can be achieved.
Popular things to change are color values, font-sizes, and widths as seen on multiple examples in Chris Coyier’s article “CSS Custom Properties and Theming” on CSS Tricks.
But there are also other properties that produce useful effects when changed, such as blurring an image with filter effects as demonstrated by Wes Bos on day 3 of his excellent JavaScript30 series.
Another great example of making use of CSS properties is what Dave Rupert named the “Cheapass Parallax Effect”, which creates a lightweight parallax effect by changing opacity and transform when the user scrolls down.
Boosting Animations
Being able to use this type of dynamic values is a great advantage when it comes to creating animations on the web. But CSS properties can also help achieving better performance in animations, by leveraging their capability of affecting multiple elements that share the same variable. This goes for both pure CSS animations, as well as those also using JS.
For example, when animating with JS: Instead of updating an inline style on every element each time a value need to change, a CSS variable can be set to just update an inline style on the root element.
Resources
- Theming With Variables: Globals and Locals by Anders Galante on CSS Tricks, March 2018
- Everything you need to know about CSS Variables by Ohans Emmanuel on freeCodeCamp, February 2018
- Learn CSS Variables, a free interactive Scrimba course by Per Harald Borgen, February 2018
- Getting Hardboiled with CSS Custom Properties by Andy Clarke on 24 Ways, December 2017
- Animating with CSS Variables by Val Head, July 2017
- Using CSS variables correctly by Mike Riethmuller, June 2017
- Locally Scoped CSS Variables: What, How, and Why by Una Kravets, June 2017
- CSS Variables a New Hope by Mauricio Palma CSSConf Budapest, 2017
- It’s Time To Start Using CSS Custom Properties by Serg Hospodarets on Smashing Magazine, April 2017