DEV Community

Cover image for Grayscale Color Palette with Equal Contrast Ratios
Bence Szabo
Bence Szabo

Posted on

Gray Rgb Grayscale Color Palette with Equal Contrast Ratios

Ever needed a grayscale color palette for different surfaces, shadows, or states in your web app? I created a little utility to generate such palette.

tl;dr: Scroll to the end to get the list of colors

But what's the big deal?

I'm glad you asked. I could have just simply created a palette that started from black #000000, and stepped through to white #ffffff with let's say increments of #080808. So something like (remember hexadecimal):

  • #000000
  • #080808
  • #101010
  • #181818
  • ...
  • #ffffff

But this feels a bit off, mostly because we humans don't perceive colors as hexadecimal representations. Qualities like hue, saturation and lightness are much better interpretations of human color perception. When you compare two different gray colors against each other they will only differ in lightness. A common method to measure difference in lightness is calculating the contrast ratio.

So how is color contrast ratio calculated?

The WCAG contrast ratio definition says:

contrast ratio
(L1 + 0.05) / (L2 + 0.05), where

  • L1 is the relative luminance of the lighter of the colors, and
  • L2 is the relative luminance of the darker of the colors.

Contrast ratios can range from 1 to 21 (commonly written 1:1 to 21:1).

Actually, I already wrote an in-depth article about calculating the color contrast ratio, see below if you're interested:

All in all, the method to calculate the contrast ratio was already given.

Creating an equi-contrast color palette

My goal was to create a gray color palette on which each color against its adjacent color has the same contrast ratio. To generate such palette I only needed to step through the gray RGB space and store the colors that had enough contrast against the previous palette color. I picked the default contrast value of 1.10362 (that is roughly 1.1) so that the palette spans from #000000 to exactly #ffffff and consists of 30 individual colors. You can see the result in the embedded CodePen below, but feel free to play around by opening the Pen in Edit mode and modifying the value of CONTRAST_RATIO in the first line of JS 🙂

Top comments (4)

danroc profile image
Daniel da Rocha

Hey Ben, thanks for your tool and article!
However, I got a bit confused as to which contrast ration to use. Looking at your tool, I see I can adjust the contrast ratio, but that feels quite arbitrary to me. Especially when you have to use 5 decimal points for that.

Would it have the same effect if, instead, you asked: how many gray steps do you want? and derive a contrast ratio from that?

finnhvman profile image
Bence Szabo

Hey Daniel, you can use any contrast ratio you would like, you don't need to go 5 decimals. Try 1.1, or 1.2, etc. The only reason I used such an arbitrary number is to span out the palette to exactly white #ffffff. Otherwise the last color will be something like #f8f8f8, I guess that could be good enough for most use-cases.

I thought about making it so that you would only need to input the number of steps, but that would require some more math (creating the inverse of a non-linear function, see my other post I embedded). In the end that would produce the same contrast ratio.

If you think about it, these colors are a Geometric Progression of (luminance value + 0.05), where the first number is 0.05 (black) and the last is 1.05 (white). So the scale factor is 0.05 and the common ratio of the geometric progression will be the contrast ratio we're looking for. To get n + 1 number of colors we only need to find the nth root of 1.05/0.05 = 21, which will always be a Real Number.

txmur profile image
Thomas X. Murray

Nice palette! Have you seen ColorBox by Lyft Design? Also great for creating non-linear stepped palettes.

finnhvman profile image
Bence Szabo

Thanks! I haven't seen it yet, but OMG it's an amazing tool!