Getting started with CSS Variables
CSS Variables are on their way to prime time in front-end development. Pre-processor variables are something that most front-end developers are already familiar with but this new feature is a little different.
Note: I’m going to be referring to Sass in this post but the examples would apply to LESS, Stylus, or anything else you might use.
Pre-processor variables
Developers have long felt the need for variables in their stylesheets. This
makes sense! We use them in almost all of the other languages that we use. They
can reduce duplication, simplify code, and give values a great semantic meaning
($font-size-base
as opposed to 16px
). This desire was partially solved with
the introduction of variables in pre-processors like Sass.
Sass variables are great but they have one big limitation: they have to be set before the styles are even sent to the browser. This is why calling them “variables” has always been a little misleading. Calling them “constants” would probably be more accurate to what these values represent.
CSS variables
Enter the new kid on the block: CSS Variables. Instead of relying on our pre-processors to do this dirty work for us, what if CSS itself had a concept of variables? That’s what the W3C team set out to solve (a process that started quite a few years ago).
Technically, CSS variables are actually considered custom properties. They use a brand-new syntax that might be a little perplexing to those that are used to the Sass counter part.
Variables are defined like this:
--custom-property-name: value;
And are used like this:
property: var(--custom-property-name)
Here is a basic example:
:root {
--font-family-serif: Times;
}
header {
font-family: var(--font-family-serif);
}
It’s important to note that the above example is valid CSS. Our custom property
doesn’t need to be processed before serving the CSS file to the browser. It’s as
valid as explicitly writing Times
as the value.
header {
font-family: Times; /* valid CSS */
font-family: var(--font-family-serif); /* valid CSS */
font-family: $font-family-serif; /* invalid CSS */
}
Root pseudo-class
You can declare CSS variables on a pseudo-class defined as :root
if your
variable is more global in nature and does not belong to a particular class or
element.
In our example above we use the :root
declaration to store our serif
font-family in.
Inheritance
Because custom properties are valid CSS they follow the same inheritance rules of other CSS properties. This means we can overwrite CSS variables by simply redefining the value (just like we would do for, say font sizes).
Expanding on our font family example:
:root {
--font-family-heading: Times;
}
.fancy-heading {
--font-family-heading: Helvetica;
}
h1,
h2,
h3 {
font-family: var(--font-family-heading);
}
Any heading that uses the .fancy-heading
class will use Helvetica instead of
Times as its font. This is awesome! We don’t need to redefine the font-family
declaration on our headings we just need to change the CSS custom property
value.
Dynamic properties
Now that we’ve gotten a taste of how we can modify CSS variables with classes we can explore what I’m going to describe as “dynamic CSS variables”. What I mean by this is that I’m not going to modify a custom property via a class name. Instead, I’m going to create custom properties that dynamically react to the browser.
Here’s a simple example of a content wrapper that uses different content padding dependent on the viewport size (Sass):
$site-padding-small: 1rem;
$site-padding-medium: 2rem;
$site-padding-large: 3rem;
.content {
padding: $side-padding-small;
@media screen and (min-width: 769px) {
padding: $site-padding-medium;
}
@media screen and (min-width: 1200px) {
padding: $site-padding-large;
}
}
Using a custom property allows us to abstract the logic from our class styling to another, more appropriate area:
:root {
--site-padding: 1rem;
}
@media screen and (min-width: 769px) {
:root {
--site-padding: 2rem;
}
}
@media screen and (min-width: 1200px) {
:root {
--site-padding: 3rem;
}
}
.content {
padding: --site-padding;
}
Our .content
class now only has a single style defined on it. Awesome! This is
just a small example on an extremely simple class. The real benefits to this
kind of optimization will come from more complex, real-world stylesheets.
Browser support
Okay, unlike CSS Grid Layout the outlook for CSS Variables isn’t as great.
The good news: we get green across the board for:
- Chrome (+ Chrome for Android)
- Firefox
- Safari (+ iOS Safari)
- Opera
- Android Browser
The bad news: no version of Internet Explorer (including Edge) currently supports this. Microsoft’s Edge team is currently working on it but lacking support for IE 11 may be a deal breaker for a lot of folks.
You may be able to get around the lack of IE/Edge support by utilizing CSS
@supports
but that might not be an option for some of you.