Published at
Updated at
Reading time
3min
This post is part of my Today I learned series in which I share all my web development learnings.

As far as I see, it's time to ditch hsl() and use oklch() for color palettes and design systems. Why's that?

For me, it boils down to two reasons.

New devices and monitors can display colors that aren't defined in the sRGB color space used by rgb(), hsl() or hex colors. Isn't it sad that you can't express these vibrant colors in CSS using existing color methods?

It is. And the solution are new CSS color functions that can talk new and fancy monitor tech (namely wide-gamut P3 colors). It's party time y'all โ€” the web gets a color update with fresh and vibrant colors.

There's oklch(), oklab() and also color() to target the wider color space, but let's focus on oklch() because it's the most user-friendly.

oklch()'s parameters (lightness, chroma and hue) are easy to grasp and feel very similar to hsl() (although chroma and saturation are two pair of shoes).

But coming back to the wider color space, if you want to see them in action with oklch(), oklch.com from the Evil Martians is the place to go. You can inspect and convert colors from and to oklch(). Unfortunately, neither my external display nor my old MacBook can display P3 colors, but if you're on recent hardware, you might see very vibrant colors on the site.

Screenshot of oklch.com which shows a very vibrant oklch pink next to a ping in hex colors.

And while vibrant colors are already a good reason for ditching hsl() in favor of oklch(), another reason outweighs the funky colors.

As already mentioned, the lch in oklch() stands for lightness, chroma and hue. And if you now modify the hue angle of oklch() colors, they keep their perceived lightness.

Can that be true? I had to see if this holds. And here's my investigation.

hsl(46 91% 66%)
oklch(87.5% 0.143 92)

Change the hue angle of these almost identical colors, and see that a hsl() color can drastically change its lightness, while the oklch() color stays almost the same.

And to prove the point, here's a color palette rotating hue angles of hsl() and oklch() colors...

hsl()
oklch()

... and here are two CSS color gradients spanning a 180 degree hue angle.

hsl()
oklch()

A 45 degree hue change can sometimes lead to very different colors depending on the color function. And these differences are fine.

But it's not cool that hsl() colors change their perceived lightness when you rotate the hue angle. An hsl() blue with the same saturation and lightness is much darker than a yellow. You can't just change a blue card component to a red one and expect that text stays readable. Booh! ๐Ÿ‘Ž

oklch() colors, on the other hand, retain their lightness. A blue with the same lightness and chroma feels as light as a yellow. You can trust the color function not to make colors much lighter or darker. Yay! ๐Ÿ‘

And to prove the point, if you then turn on the grayscale, you'll see that oklch() colors with similar lightness and chroma values stay almost on the same gray tone. They're not changing in perceived lightness. Fancy!

So in summary, when you need to manipulate colors and want to avoid color contrast issues, oklch() is your friend from now on!

But can you use it today? Absolutely.

MDN Compat Data (source)
Browser support info for oklch() (OKLCH color model)
chromechrome_androidedgefirefoxfirefox_androidsafarisafari_iossamsunginternet_androidwebview_android
11111111111311315.415.422.0111

Have fun coloring!

Was this TIL post helpful?
Yes? Cool! You might want to check out Web Weekly for more quick learnings. The last edition went out 13 days ago.
Stefan standing in the park in front of a green background

About Stefan Judis

Frontend nerd with over ten years of experience, freelance dev, "Today I Learned" blogger, conference speaker, and Open Source maintainer.

Related Topics

Related Articles