loading...

Shifting Color Palettes using the LCH Color Space

dimfeld profile image Daniel Imfeld Originally published at imfeld.dev on ・4 min read

Update: Since originally writing this post I've developed my own tool
to automate this process. Check it out at https://palettes.imfeld.dev!

Almost every web developer has heard of the RGB system of representing colors, which is a direct corollary to how colors are represented in video hardware. Many of us are familiar with HSL as well, in which a color is made up of hue (the raw color), saturation (how much white is mixed in to the color), and lightness.

These methods have served us well enough, but ultimately they are not very useful when you want to take a color value, modify it in some way, and have a good idea of how the resulting color will look. In the color world, they say that these color spaces are not perceptually uniform.

This is a well-known problem, and I most recently encountered it on the Tailwind CSS website when I was looking up how to create my own color palette in the same way that Tailwind's built-in palettes work.

Bad news: color is complicated and we've yet to find a tool that does a good job generating these sorts of color palettes. We picked all of Tailwind's default colors by hand, balancing them by eye. Sorry!

At work, our existing site uses the Angular Material Blue-Gray palette, mostly the primary 500 color. I tried copying the entire palette into my Tailwind CSS config, but as more colors were used the results looked drab. Worse, the Tailwind UI components that I have been using tend to use 600 as their primary shade, so everything was rather dark without extra work to shift the color palette.

The entire Material blue-gray palette:

So I was left with the question of how to make a palette which is consistent with the existing website, but also looks like something that I would want to use. My initial decision was just to punt on the decision and figure it out later.

A few days later, Lea Verou wrote a blog post about using the LCH color space in CSS, and also published a great color tool for playing with LCH. LCH, like the somewhat-better-known color space LAB, is a perceptually uniform color space. This means that the non-lightness values do not affect the eye's perception of a change in the lightness value (say, changing the lightness from 75% to 50%) of the color. HSL does not have this property, so the same change in lightness of two HSL color values will not generate a similar-looking difference in the colors. If you're curious about more details, Lea's post does a great job of explaining LCH and how it differs from RGB and HSL.

This seemed like the answer to my dilemna, so I gave it a try. I started with Material blue-gray 500, RGB value #607d8b:

Lea's color picker says this color has an LCH value of lch(50.534% 13.837 234.058). The first value there is the lightness, and the second and third values are the "Chroma" and "Hue," somewhat similar to the Saturation and Hue of HSL. (Again, Lea's post explains this better.)

From there, I took the Tailwind UI "indigo" color palette as my base and copied each color into the LCH color tool. Here, I only cared about getting the lightness values:

50 — 96.372% lightness

100 — 93.54% lightness

200 — 87.18% lightness

300 — 79.92% lightness

400 — 67.781% lightness

500 — 53.349% lightness

600 — 42.773% lightness

700 — 37.477% lightness

800 — 29.641% lightness

900 — 23.662% lightness

From there, I used the LCH color tool to create a palette with the Hue value of the Material Blue-Gray 500 color, but the Lightness and Chroma values taken from Tailwind's Indigo palette. LCH is not yet widely supported in browsers, so I copied the RGB values out of the tool, and put the resulting palette into my Tailwind config.

lchBlueGray: {
  50: 'rgb(91.1% 96.96% 100%)',
  100: 'rgb(83.93% 94.59% 100%)',
  200: 'rgb(75.61% 87.74% 93.82%)',
  300: 'rgb(67.77% 79.75% 85.73%)',
  400: 'rgb(55.01% 66.73% 72.52%)',
  500: 'rgb(40.41% 51.84% 57.38%)',
  600: 'rgb(30.15% 41.39% 46.73%)',
  700: 'rgb(25.15% 36.32% 41.54%)',
  800: 'rgb(17.9% 29.04% 34.08%)',
  900: 'rgb(12.44% 23.68% 28.56%)',
}

And this is how it looks! I like this better because the different shades retain more of the blue of the middle color, while I didn't have to guess to make the brightness match the existing palettes that the Tailwind UI components come with.

Compared to the Material Blue-Gray palette I was coming from:

And once again, Tailwinds UI's Indigo:

Many thanks to Lea Verou for putting together such an easy-to-use tool!

Posted on Jun 16 by:

dimfeld profile

Daniel Imfeld

@dimfeld

I'm the cofounder and software/data lead at Carevoyance, creating new ways to explore and visualize complex data.

Discussion

markdown guide