The goal I had in mind was to have maximized text contrast against any color. This meant the text color should contrast well, but also I wanted a supportive translucent background to help bump that contrast even further, for situations where it may have otherwise had low contrast.
To do this:
- I find a good contrasting text color with
color-contrast()
. - Then I find a contrasting color for that text color with
color-contrast()
. - Use that text contrast color as a supportive translucent background with relative color syntax
oklch(from black l c h / 40%)
tldr;
- If the text color is white, it's supportive background should be translucent black.
- If the text color is black, it's supportive background should be translucent white.
It's so much easier to see, but you can try it here:
See how I've automated the text color and a supportive background on that text? I don't have to care about the color I'm overlaying now, the browser handles all of it dynamically!
The essentials of the effect #
I use 2 future CSS features that aren't well supported yet (but are very fun to play with):
Safari Tech Preview is the only browser with support for relative color syntax at the time of writing this post. Chrome Canary has color-contrast() support but won't have the dynamic supportive background (see generic bg in CSS below).
First, the container background needs to be in a custom property so we can share it with other functions:
section {
--bg: hsl(var(--hue) 50% 50%);
}
Then, the h1 need to put it's contrasting text color into a custom property so we can share it too:
h1 {
/* pick either black or white based on --bg */
--text: color-contrast(var(--bg) vs black, white);
color: var(--text);
/* generic semitransparent bg */
background: hsl(0 0% 0% / 40%);
}
For the cherry on top, if the browser understands relative color syntax, then create a new semi-transparent color from the contrasting color of --text
.
/* if relative color syntax is supported */
@supports (background: hsl(from red h s l)) {
h1 {
/* pick either black or white
depending which contrasts with --text,
extract it and make it 40% semitransparent */
background: oklch(from color-contrast(var(--text) vs black,white) l c h / 40%);
}
}
All of it together:
@layer demo {
section {
--bg: hsl(var(--hue) 50% 50%);
}
h1 {
--text: color-contrast(var(--bg) vs black, white);
color: var(--text);
background: hsl(0 0% 0% / 40%);
}
@supports (background: hsl(from red h s l)) {
h1 {
background: oklch(from color-contrast(var(--text) vs black,white) l c h / 40%);
}
}
}
Conclusion #
There you have it, dynamically contrasting text with a supportive translucent background. I think that's pretty rad stuff.
Here's the Codepen embedded, so in the future it'll just work 🤓