A set of wind farm turbines against bright green hills

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:

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 subtlewill 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:

  1. 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:

  2. Use supports for browser detection

    You 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.