Getting started with CSS Custom Properties

Categories

Custom properties in CSS are exceptionally useful, not just for tokenising your CSS, but also for abstracting complexity and interactivity into smaller, easier to manage pieces. This short guide will get you up to speed with how they work and how to use them.


Say you’ve got some CSS like this:

Code language
CSS
h1 {
  background: goldenrod;
}

p {
  color: goldenrod;
}

.my-element {
  border: 1px dotted goldenrod;
}

There’s a lot of repetition in there, but how do you improve that with native CSS? You can use CSS Custom Properties—also known as CSS variables—to abstract and tokenise your CSS to make your code more manageable.

Code language
CSS
:root {
  --primary: goldenrod;
}

h1 {
  background: var(--primary);
}

p {
  color: var(--primary);
}

.my-element {
  border: 1px dotted var(--primary);
}

In this tutorial, we’re going to get a grip of the basics of custom properties and learn some of the extremely cool and helpful stuff they can do and how they can help your projects.

The basics permalink

Let’s start right from the top and look at some basics. A custom property is just like a normal CSS property and value pair: a declaration. These declarations are defined inside a CSS rule.

Code language
CSS
:root {
  --text-color: rebeccapurple;
}

What the heck is a :root? It is a pseudo-class which represents the root of the document tree, which most of the time means the <html> element. If you are in a Custom Element, using the shadow DOM, though: the :root will represent the root of the shadow DOM instead of the <html> element.

Once a custom property is defined, you can grab the value of it, using the var() function. This will retrieve the current computed value of the property, which we’ll cover in more detail, later in this tutorial.

With the combination of a declared custom property and the var() function, we can use them in our CSS to apply values, like this:

Code language
CSS
:root {
  --text-color: rebeccapurple;
}

h1 {
  color: var(--text-color);
}

Fallbacks permalink

If a custom property value hasn’t been defined or it is invalid, the initial or inherited value will be used instead. This can result in some pretty lousy looking user interfaces, so a good shout is to provide a fallback to the var() function.

Code language
CSS
h1 {
  color: var(--text-color, royalblue);
}

By passing a second, fallback value, the <h1> will be royalblue if the --text-color custom property has not been defined.

Fallbacks are handy as heck, but they aren’t used by browsers that don’t support custom properties. For the microscopic share of browsers that don’t support custom properties, you can use custom properties as a progressive enhancement, like this.

Code language
CSS
h1 {
	color: royalblue;
  color: var(--text-color, royalblue);
}

We still have to pass a fallback to the var() function because as we just learned, an invalid value—which includes undefined custom properties—will result in the initial or inherited value being used.

Custom properties are computed permalink

Once you set a value for a custom property, it can be changed in context and just like any other declaration—a property and value pair—it will be affected by specificity and the cascade.

Take the first example as a context:

Code language
CSS
:root {
  --text-color: rebeccapurple;
}

h1 {
  color: var(--text-color);
}

If this <h1> was inside an <article> with a class of .colour-change, which has a CSS rule, declaring a value for --text-color: that value would be applied.

Code language
CSS
:root {
  --text-color: rebeccapurple;
}

h1 {
  color: var(--text-color);
}

article.colour-change {
  --text-color: seagreen;
}

This CSS is applied because .article.colour-change has a higher specificity than :root.

You can set custom properties with JavaScript permalink

This ability to contextually override a custom property makes them incredibly useful for interactive states and generally writing less CSS. The previous demo used a toggled CSS class to contextually set a custom property value, but you can also set them inside your JavaScript:

Code language
JavaScript
const article = document.querySelector('article');
const button = document.querySelector('button');

button.addEventListener('click', (evt) => {
  article.style.setProperty('--text-color', 'tomato');
});

The <article> gets the value for --text-color applied in its style attribute, which gives it a way higher specificity than :root.

Wrapping up permalink

This quick intro to Custom Properties has hopefully given you the knowledge and confidence to explore them further. If you want to learn more about them, I recommend the following resources:

Until next time, take it easy 👋


Comments

Hello, I’m Andy and I’ll help you build fast, accessible websites & design systems.

I’m a freelance CSS and design systems consultant, based in the UK. I specialise in design systems and creative web design, such as landing pages and campaign work.

I’m currently helping Google by refactoring the CSS and creating a design system for web.dev, but I have availability for projects such as small websites, landing pages and consultancy. I will have full availability for larger projects in January 2022.

Hire me