We posted not long ago about the difference between native CSS variables (custom properties) and preprocessor variables. There are a few esoteric things preprocessor variables can do that native variables cannot, but for the most part, native variables can do the same things. But, they are more powerful because of how they are live-interpolated. Should their values ever change (e.g. JavaScript, media query hits, etc) the change triggers immediate change on the site.
Cool, right? But still, how actually useful is that? What are the major use cases? I think we’re still seeing those shake out.
One use case, it occurred to me, would be theming of a site (think: custom colors for elements around a site). Rather than writing different CSS for a bunch of different themes, or writing JavaScript that targets all the elements we intend to change and changing them), we just write one base set of CSS that utilizes variables and set those variables to the theme colors.
Imagine we allow the header and footer background of our site to be customized.
header {
background: var(--mainColor);
}
...
footer {
background: var(--mainColor);
}
Maybe there is a subheader with a darker variation of that color. Here’s a little trick to lay a transparent layer of color over another:
.subheader {
background:
/* Make a bit darker */
linear-gradient(
to top,
rgba(0, 0, 0, 0.25),
rgba(0, 0, 0, 0.25)
)
var(--mainColor);
}
Where does --mainColor
come from?
With theming, the idea is that you ask the user for it. Fortunately we have color inputs:
<input type="color">
And you could store that value in a database or any other storage mechanism you want. Here’s a little demo where the value is stored in localStorage:
The value is plucked out of localStorage
and used when the page loads. A default value is also set (in CSS), in case that doesn’t exist.
What makes the above demo so compelling, to me, is how little code it is. Maintaining this as a a feature on a site is largely a CSS endeavour and seems flexible enough to stand the test of time (probably).
Not unusually, I was way behind on this one.
Lots of people think of theming as one of the major use-cases for CSS Custom Properties. Let’s look at some other folks examples.
Giacomo Zinetti has the same kind of color-picker implementation
Examples and advice from Harry Roberts
He wrote “Pragmatic, Practical, and Progressive Theming with Custom Properties”, in which he pointed to apps like Twitter and Trello that offer theming directly to users:

Harry does a lot of consulting, and to my surprise, finds himself working with companies that want to do this a lot. He warns:
Theming, the vast majority of the time, is a complete nice-to-have. It is not business critical or usually even important. If you are asked to provide such theming, do not do so at the expense of performance or code quality.
In Sass / In React
In a real-world application of theming through Custom Properties, Dan Bahrami recounts how they did it on Geckoboard, the product he works on:

It’s a React product, but they aren’t using any styles-in-JavaScript stuff, so they opted to do the theming with Custom Properties, through Sass.
@mixin variable($property, $variable, $fallback) {
#{$property}: $fallback;
#{$property}: var($variable);
}
So they can do:
.dashboard {
@include variable(background, --theme-primary-color, blue);
}
Which compiles to having a fallback:
.dashboard {
background: blue;
background: var(--theme-primary-color);
}
They also created react-custom-properties which all about applying Custom Properties to components, taking advantage of the fact that you can set Custom Properties as inline styles:
<div style="--theme-primary-color: blue;">
</div>
More than one color and property
It’s not only colors that can change, a Custom Property can be any valid value. Here’s Keith Clark with a demo with multiple colors as well as font size:
And David Darnes with theming built into a Jekyll site:
Microsoft Demo
Greg Whitworth created this demo (offline now, sorry):

Which uses color modifiers within color functions themselves:
.distant-building__window {
fill: rgb(
calc(111 + (111 * var(--building-r-mod))),
calc(79 + (79 * var(--building-g-mod))),
calc(85 + (85 * var(--building-b-mod)))
);
}
Which is not supported in all browsers.
Greg also pointed out that CSS4 color functions (which we’ve covered before), will make all this theming stuff even more powerful.
The Polymer Project themes through Custom Properties
At least it did in the v1 docs. The idea is that you’d have a web compontent, like:
<iron-icon icon="[[toggleIcon]]">
</iron-icon>
That had smart defaults, but was specifically built to allow styling via theming:
<style>
iron-icon {
fill: var(--icon-toggle-color, rgba(0,0,0,0));
stroke: var(--icon-toggle-outline-color, currentcolor);
}
:host([pressed]) iron-icon {
fill: var(--icon-toggle-pressed-color, currentcolor);
}
</style>
Which meant that you could set those variables and have the component take on new colors.
Support and fallbacks
Support has gotten pretty good recently:
This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.
Desktop
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
49 | 31 | No | 16 | 10 |
Mobile / Tablet
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
119 | 119 | 119 | 10.0-10.2 |
Opera Mini and IE are notably missing. We already covered the idea of a fallback through setting a valid non-variable property before the one using a Custom Property.
Like many modern CSS features, you can use @supports
to test for support before using:
@supports (--color: red) {
:root {
--color: red;
}
body {
color: var(--color);
}
}
It always depends on the situation, but just putting fallbacks on a previous declaration is probably the most useful way to deal with non-support in CSS. There are also edge cases.
Michael Scharnagl documents a JavaScript method for testing:
if (window.CSS && window.CSS.supports && window.CSS.supports('--a', 0)) {
// CSS custom properties supported.
} else {
// CSS custom properties not supported
}
Colors and Accessibility
When setting colors for text, and the color behind that text, the contrast between those colors is an accessibility issue. Too little contrast, too hard to read.
One somewhat common solution to this is to choose whether the text should be light or dark (white or black) based on the color behind it.
David Halford has a demo calculating this with JavaScript:
And Brendan Saunders with Sass:
Has anyone examined the performance impact of using more than a handful of custom properties? I’d like to use them in an upcoming project, but it may be a hard sell if they get janky at scale.
Using custom properties to set a single property is ALWAYS going to be faster than manipulating styles on each individual DOM node that needs the custom styles.
Like, nearly 100x faster: https://jsperf.com/css-variables-vs-inline-styles
I don’t really get this section:
All
@supports
does is a parser level check for support, the linked version works just fine. Additionally, theCSS.supports()
method actually utilizes the same underlying code as@supports
; so it is the same as using it declaratively in your CSS. This can still be counted on to determine if a browser supports custom properties or not because it would fail if it isn’t able to parse it.I fixed that part! I had read this and was like awwwwwwshit, that’s weird. But I guess that’s all about setting a variable to another variable?
@chriscoyier
Yeah, it can be kind of confusing but the variable existing or not is irrelevant, remember you’re only testing if the parser works with custom props, not the capability of the cascade and all of the other factors of custom properties. I cover this in the Detecting support for Custom Properties section of the post. You could literally do the following which is self commenting:
Here’s a jsbin of the above and screenshot with Edge/IE11
Hope that helps clarify.
@chriscoyier
Also, thanks for the shoutout about the demo. Since I noticed you’re on a browser that has the calc() issues, I posted a gif of it in action on twitter. I also want to note that while I did the coding work, all of the wonderful design work was done by Stephanie Drescher :)
The ‘little trick’ to darken your
--mainColor
is brilliant and I intend to steal it without shame. I’ve been playing with CSS variables in a little side project and was going through picking out a palette and this just simplifies everything.Pity you can’t apply the same technique to auto-adjust text colors.
I love the trick with darken color too! Thanks Chris!
Yesterday I built a snippet generator that uses the power of custom properties. Have a look guys:
https://pawelgrzybek.com/snippet-generator/
Few months back I took an advantage of it to create a newt color switcher as well:
Demo:
Article:
https://pawelgrzybek.com/css-custom-properties-explained/
Hey Chris,
Feeling honoured to be mentioned in a CSS-Tricks article! Thanks for the shoutout. You may be interested that React 16 will support setting custom properties directly in an element’s
style
prop. For example…<div style={{ ‘--my-color’ : ‘red’}} />
Great article, been playing around with this stuff recently some cool use cases.
Also worth mentioning the built in fallback for if the var is not set.
color: var(--text-color, black);
If
--text-color
is not present in the code it will default toblack
https://developer.mozilla.org/en-US/docs/Web/CSS/var#Browser_compatibility
I did this on my portfolio about 8 months ago:
http://jsil.work/
I hooked a slider element to the hue value in HSL using jQuery. And then used the variable in a SVG and css elements.
Thanks alot for the articles, almost all of the code I used I mined from CSS Tricks.
I want to work this into my wordpress templates, my thinking is write to local storage like this article and also save into the database with the customizer api.
That way users can see there changes on the fly. Can anyone see any problems with this approach? This would make my wp sites more wixy for my clients but still retain all of the wp benefits
So I made this happen,
Didnt use the local storage as the customizer api has it’s own preview callback. Have to admit its pretty magical being able to see colors and fonts change from the customizer. Its super smooth and ive got sass fallbacks for IE etc.
Here was my workflow:
1. Setup new fields in the wordpress customizer
2. Setup js preview postMessage callbacks – check out this article:
https://code.tutsplus.com/tutorials/customizer-javascript-apis-getting-started–cms-26838
3. Write the saved fields to admin-ajax variables.
4. Set these variables when the page loads
Note – you will need to implement a preloader if you dont want people to be able to see colors change (I preferred to set the css variables async)
Great article and demo by Stephanie Liu:
http://ramenhog.com/blog/2017/06/07/theming-with-css-custom-properties