RSS FeedTwitterMastodonBlueskyShare IconHeart IconGithub IconArrow IconClock IconGUI Challenges IconHome IconNote IconBlog IconCSS IconJS IconHTML IconShows IconOpen Source Software IconSpeaking IconTools IconShuffle IconNext IconPrevious IconCalendar IconCalendar Edit IconNotebook IconObservable Notebooks IconSlash IconGoogle G IconYouTube IconEye IconComment IconAI Icon
Screenshot of the final code snippet from this blog post.
A cartoon skull with a hotpink hat on.4 min read

A color-contrast() strategy for complimentary translucent backgrounds

css
6,818 views · 5 active

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:

  1. I find a good contrasting text color with color-contrast().
  2. Then I find a contrasting color for that text color with color-contrast().
  3. Use that text contrast color as a supportive translucent background with relative color syntax oklch(from black l c h / 40%)

tldr;

  1. If the text color is white, it's supportive background should be translucent black.
  2. 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):

  1. color-contrast() - spec
  2. "Relative color syntax" - spec

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 🤓

388likes
75reposts