I saw in the release notes for Safari Technical Preview 122 that it has support for a color-contrast()
function in CSS. Safari is first out of the gate here. As far as I know, no other browser supports this yet and I have no idea when stable Safari will ship it, or if any other browser ever will. But! It’s a very good idea! Any native tool to get us to ship more accessible interfaces (of which color contrast is a part) is cool by me. So let’s attempt to get it to work.

Anybody can download Safari Technical Preview, so I did that.
I had to ask around about this, but just because this is a pre-release browser, it doesn’t mean all these features are active by default. Just as Chrome Canary has feature flags you have to turn on, so does Safari Technical Preview. So, I had to flip it on like this:

The release notes don’t have any information about how to actually use color-contrast()
, but fortunately web searching turns up a spec (it’s part of Color Module 5), and MDN has a page for it with very basic syntax information.
This is how I understand it:
That example above is a little silly, because it will always return white
— that has the most contrast with black
. This function actually gets useful when one or more of those color values is dynamic, meaning very likely it is a CSS custom property.
The function returns a color, so the top use-case, I would guess, is going to be setting a color based on a dynamic background. So…
section {
background: var(--bg);
color: color-contrast(var(--bg) vs white, black);
}
Now we can toss any color at all at --bg
and we’ll either get white or black text, depending on what has the most contrast:

That’s extremely cool, even in the most basic use case.
Here’s a demo from Dave where he’s not just setting the text color in the parent, but the color of links as well, and the links have a different set of colors to choose from. Play with the HSL sliders (in Safari Technology Preview, of course) to see it work.
Just picking two colors that have enough contrast is easy enough (although you’d be surprised how often it’s screwed up by even those of us with good intentions). But oh wow does it get complicated quick with different situations, let alone having a bunch of color variations, or god forbid, arbitrary combinations.
Here’s a video of me playing with Dave’s tester so you can see how the colors update at different places.
i wonder if you can nest color-contrasts, by putting the result of one color contrast into a variable and putting that into another. what usecase would come out of it?
I would expect that it works, but I don’t really know. One level deep doesn’t seem entirely farfetched to me. Like maybe you have a set of greens that you pick the best-contrasted version from. And reds, and yellows, etc. Then have one function that picks between the hues.
Hi, thank you for the article. I can’t wait for this to be available on all major browsers.
I also wrote about the new color features here: https://dev.to/fabiogiolito/create-a-color-theme-with-these-upcoming-css-features-4o83
There are some different approaches in there that you may find interesting.
Oh, fantastic! I’ve had to do this manually so automating it will be a time-saver. A couple of questions come to mind…
Can you control the contrast threshold?
How will this work with color filters?
Do we know if other browsers plan to support this as well? Any rumblings of an ETA?
Thanks as always for the great inspiration!
This is a prime candidate for a PostCSS plugin to polyfill this feature to all browsers. I had a quick look but didn’t see one that replaces the
color-contrast()
syntax. It would obviously have to deal with or ignore instances with CSS custom properties but it would be a step in the right direction.Will it work for SVGs? One SVG could serve as the logo for a website AND as the favicon without worrying if the logo will disappear into various background colors.