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.
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:
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:
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