Contrast is boring—can't someone else do it?

Having sufficient contrast in your website is one of those things which are very important but still very boring to fix—especially if your site uses multiple background colours. Well, be bored no more! color-contrast() is (hopefully soon) here to save us! Let's learn what it does.

3 min read


By Magnus Rand


December 12, 2022

Contrasty text automagically!

Making sure your text is readable isn't always easy. However, with the use of some color-contrast() magic, you can make sure your text always passes WCAG AA standards. Let's look at a simple example on how to use it:

Simple example

Let's say we have a very simple site which consists of a heading, a paragraph, and a background.

<h1>"Welcome to my World"</h1>
<p>It's a wild one</p>

In this site, we want to make sure the text colour always has enough contrast to be legible—regardless of what our background colour is. We could, of course, check our colours on a contrast-test site but that is too much work. Let's instead use color-contrast():

:root {
  /* a variable for the background colour*/
  --bg-colour: navy;

body {
  background-color: var(--bg-colour);

/* selects both h1 and p elements*/
:is(h1, p) { 
  color: color-contrast(var(--bg-colour) vs black, white);

Let's see … Now, what does that last styling do? Well, color-contrast() is, simply put, a function that returns a colour. The returned colour is based on two things: the colour to compare contrast against and a set of colours to choose from. In this example, --bg-colour, or navy, is what to compare against, and black and white are the colours to chose from. The result is what you see below:

A site showing the text from the example in a white colour on a navy background
Result from example code

We can see our text is in a nice and contrasty white. And all this was done without us knowing if black or white had the most contrast againts navy. Great!

AA level contrast against a palette

In the previous example, the text colours to choose from was either black or white as this will always achieve the highest contrast level. However, in the real world you might need to follow a palette of colours while also achieveing WCAG AA level contrast. Again, color-contrast() has us covered!

Also this time, we have our simple site:

<h1>"Welcome to my World"</h1>
<p>It's a wild one</p>

But this time, we want our background colour to randomly change on each load. Let's magically🪄 add some javascript to randomly set the background to either navy, lightseagreen, orange or grey. We also want our text colour to be navy or lightseagreen, as long as it doesn't violate AA-level contrast.

To do this, we only need to change a few characters in our :is(h1, p) selector:

/* before */
:is(h1, p) { 
  color: color-contrast(var(--bg-colour) vs black, white);

/* after */
:is(h1, p) { 
  color: color-contrast(var(--bg-colour) vs navy, lightseagreen to AA););

This simple change does two things: It tells color-contrast() to pick between navy and lightseagreen, and, due to to AA, it also says the selected colour needs to satisfy AA-level WCAG. Since navy and lightseagreen alone are not guaranteed to do this, this option also adds black and white as fallback colours. Pretty neat. You can see the result below. Each change happens when the page is reloaded:

An animation showing a site with the example text. The site is reloaded multiple times and receives a new background colour each time. In response to the new background colour, the text colour is updated to ensure AA level contrast.
Results from the example

Buuuut … Support isn't great 😅

Before you go out and implement this in your site I unfortunately need to tell you that this is still an experimental feature; at the moment of writing it's actually so experimental that only Safari supports it, and even there it is behind a feature flag. But, hopefully soon, more browser will add support, and testing text contrast might be a thing of the past! See MDN Web Docs for more information on how to enable it, and try it out with the links to the given examples!

Links to examples

* You need Safari with the color-contrast() feature flag enabled to run this

Up next...