On Using Custom Properties

On Twitter, John Allsopp recently shared that Flexbox is the greatest thing that happed to CSS. I quickly chimed in with my personal favourite. To me the single greatest addition to CSS over the past 20 years is Custom Properties. They’ve opened up a ton of possibilities, and make us CSS Authors way more productive. The way they are specced — as properties and not simply variables — is pure genius and gives them their true power.


💁‍♂️ I heard spec author Tab Atkins talk about them for the first time at CSS Day 2013, but it wasn’t until Lea Verou‘s talk CSS Variables: var(--subtitle); in 2016 that it really clicked for me.


Over at CSS-Tricks, Chris Coyier writes about the Different Degrees of Custom Property Usage: how do you provide defaults, and how far do you go when splitting things up into several parts?

Regarding the fallback part Chris sticks to what we already know: a 2nd argument to var():

el {
  border: .1em solid var(--color, hsl(200deg 15% 73%));

The interesting part is on splitting things up: do you provide one single hsl color, or do you split out all the individual parts?

el {
  --color: hsl(200deg 15% 73%);
  border: .1em solid var(--color);
el {
  --color-h: 200deg;
  --color-s: 15%;
  --color-l: 73%;
  --color-hsl: var(--color-h) var(--color-s) var(--color-l);
  --color: hsl(var(--color-hsl));
  border: .1em solid var(--color);

Just like Chris I’m more leaning towards using --color here because although these Custom Properties are very nice, they do come at a cost: complexity. As I’ve tweeted back in February:

Thankfully there’s DevTools’s “Computed Styles” pane to somewhat help me out there 🙂

Additionally, settings these individual props on :root and then overriding --color-h for some specific element won’t work, because --color will already have been computed before it is passed down the inheritance tree. This is what Chris calls The Big Gotcha With Custom Properties.


Over at her blog, Lea Verou also wrote about Custom Properties and how to provide defaults. Interestingly, Lea opts to no directly use the passed in Custom Property, but resorts to something she calls “pseudo-private custom properties” that get an extra _ prefix.

My preferred solution is what I call pseudo-private custom properties. You use a different property internally than the one you expose, which is set to the one you expose plus the fallback.

Like so:

el {
  --_color: var(--color, hsl(200deg 15% 73%));
  border: .1em solid var(--_color);

As an extra she also taps into Houdini’s powerful @property to register a default value. Unfortunately Houdini is only supported in Chromium at the time of writing.

🎩 Houdini, ain't that a magician?

Houdini is a set of low-level APIs that exposes parts of the CSS engine, giving developers the power to extend CSS by hooking into the styling and layout process of a browser’s rendering engine. Houdini is a group of APIs that give developers direct access to the CSS Object Model (CSSOM), enabling developers to write code the browser can parse as CSS, thereby creating new CSS features without waiting for them to be implemented natively in browsers.

It really is magic, hence it's name Houdini. I'd recommend this slidedeck and this video to get you started


👀 Don’t try this at home

Because the contents of Custom Properties are not parsed until they are used (using var()), you can store anything in them. That means you could abuse them to create faux Single-line Comments in CSS:


Published by Bramus!

Bramus is a frontend web developer from Belgium, working as a Chrome Developer Relations Engineer at Google. From the moment he discovered view-source at the age of 14 (way back in 1997), he fell in love with the web and has been tinkering with it ever since (more …)

Unless noted otherwise, the contents of this post are licensed under the Creative Commons Attribution 4.0 License and code samples are licensed under the MIT License

Join the Conversation


Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.