Reading the incredibly useful caniuse.com the other day, I was pleased and surprised to see that CSS variables are now handled in every major browser except one. This means it is overdue for me to address the use of variables in modern development, as it will be practical to use them directly in your stylesheets in the very near future…
You’re Not the First
It’s worthwhile noting that this is not the first time variables have appeared in CSS: currentColor
, the first variable, has been around for many years. Preprocessors like Sass have also supported variables for a long time, and the CSS spec (officially called Custom Properties) has been inspired by many of the discoveries during the development and use of all three.
One of the most common use of CSS variables is defining common colors that are used repeatedly in your stylesheet, and it’s that example that I’ll start with here.
Living Color
CSS variables can be defined anywhere, but they are inherited according to standard CSS rules. That being the case, the following are logical places for defining a CSS variable:
- the universal selector (
*
) - the
body
element - the
:root
- classes
- element selectors
In practice, CSS variables can be defined on any selector; it’s the limit of inheritance that’s important.
Variable definitions are preceded with two dashes, and can be anything that consists of a word without any spaces:
body {
--alert: #cb333b;
}
This reference is later referred in the stylesheet using the var()
function to recreate the value for appropriate selectors:
h3 { color: var(--alert); }
This would set h3
elements to the color defined in the --alert
variable.
Living On The Edge
Variable references can be used inside property values that contain multiple components:
::root {
--shadowcolor: rgba(0,0,0,0.3);
}
aside {
box-shadow: 50px 50px 5px var(--shadowcolor);
}
But they cannot be concatenated with units of measurement, and unitless values can’t be defined. In other words, you cannot do something like this:
.warning {
--timing: 1;
}
.warning:hover {
background: red;
transition: var(--timing)s;
}
But this is perfectly okay:
.warning {
--timing: 1s;
}
.warning:hover {
background: red;
transition: var(--timing);
}
Variables can be used with calc
:
div {
min-height: 100px;
--boldborder: 5px;
}
.subtle {
border: var(--boldborder) solid #666;
border-radius: calc(var(--boldborder) - 1px);
}
Applied to an element with a class of subtle
will produce the apperence of a 4px border-radius
.
Trading Places
Variable definitions and references don’t have to be solely in a stylesheet: embedded and inline references are also valid. For example, in your linked CSS:
::root {
--fillet: 20px;
}
And in your HTML, an inline reference to the variable:
<div style="border-radius: var(--fillet)"></div>
Paint It Black
In Sass, the practice of variables is often extended to create key values that will be referenced repeatedly throughout your CSS. The same can now be achieved using native CSS variables:
::root {
--gutter: 1rem;
--keytext: rgba(0, 0, 0, 0.9);
--bordercolor: #333;
}
Which can be used anywhere in the CSS:
article {
margin: var(--gutter);
border: 1px solid var(--bordercolor);
}
article p {
color: var(--keytext);
}
By centralizing the variables, very quick style changes can be made to an entire site; by changing a variable value, the CSS changes in all the places it is used. No more hunting and finding values in stylesheets!
Using Variables Today
Right now, Microsoft Edge / IE is the only browser to lack native support for variables, although it is marked as being Under Development in Edge. That means that developers are very close to using native CSS variables in their front-end code. Until that day, there are two possible approaches:
- Use a post-processor with support for CSS variables. Writing your CSS and compiling it it with PostCSS, combined with cssnext, will “bake” the results into the output CSS code. That is, writing this:
:root { --keycolor: limegreen; } h1 { color: var(--keycolor); }
Will output this in CSS:
h1 { color: limegreen; }
This approach requires that any changes to the code be reprocessed through cssnext. Alternatively:
- Use
supports
for browser detectionYou can also use
@supports
to detect if the browser understands CSS variables:@supports (--test: value) { main { --bcolor: rgba(0, 0, 0, 0.3); background: --bgcolor; } }
Of course, this would mean that you’d also need to create fallbacks for browsers that do not understand CSS variables, writing them elsewhere in your stylesheet:
main { background: rgba(0, 0, 0, 0.3); }
Conclusion
CSS variables have tremendous power, and can be used most everywhere in your ste stylesheet(s), including @media
queries. Lea Verou demonstrated some of these - including some potential gotchas - in her recent CSS Conf presentation, which I strongly recommend watching. You might also want to check out Gregor Adams work on creating a grid layout using flexbox and CSS variables.
Photograph by Fotis Dimeas under a Creative Commons Attribution-NonCommercial 3.0 Unported license
Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.