Skip to content

Day 1: custom properties and fallbacks

I saw Manuel Matuzovic start up 100 days of more or less modern CSS on his own blog, and I thought it was a great idea that I wanted to give a try. I hope to use this series to familiarize myself more with CSS features that I haven't got a chance to deep dive on. I like to think of this series as my "cover album" of the great work that Manuel did!


CSS custom properties have nearly 97% browser support and as such, can be used liberally in new designs.

Let's see what happens when we try to use a variable that we haven't set yet.

.box-without-default {
  background-color: cornflowerblue;
  border: 3px solid var(--color);
  padding: 1rem;
  max-inline-size: 3.5rem;
}

Even though --color is not declared, it doesn't prevent the box from showing up with the rest of its styles. The border line is simply skipped, because the missing custom property makes that variable invalid.

But what if we wanted to specify a default?

.box {
  background-color: cornflowerblue;
  border: 3px solid var(--color, black);
  padding: 1rem;
  max-inline-size: 3.5rem;
}

The border shows up this time! The second argument that we pass to the var() function acts as a fallback whenever the property is not set. However, if the property is set, that will take precedence.

Pseudo-private custom properties

Lea Verou coined the term "pseudo-private custom properties", which use a different property name internally than the one that is exposed to authors to edit. In her examples, she uses the same property name prefixed with an underscore.

.box-pseudo-private {
  --_color: var(--color, black);
  background-color: cornflowerblue;
  border: 3px solid var(--_color);
  color: var(--_color);
  padding: 1rem;
  max-inline-size: 3.5rem;
}
hi

This is especially helpful when the same custom property and its defaults are consumed across multiple properties.

hi

@property registration

At the time of writing, @property support is under 73%. However, when it is supported there are some nice-to-haves that come along with it.

@property --box-color {
  syntax: '<color>';
  inherits: true;
  initial-value: black;
}

.box-with-property {
  background-color: cornflowerblue;
  border: 3px solid var(--box-color);
  padding: 1rem;
  max-inline-size: 3.5rem;
}

Using @property declarations have a few advantages:

  • The property can be type-checked.
  • An initial value can be set independent of the consuming var().
  • We can define whether the custom property inherits its value from declarations on its ancestors.

Related reading