I'm currently booking for my next available slot in August 2022. Get in touch.

Building accessible color palettes

The easiest way to build a WCAG 2.0 AA compliant color system

Mariano Miguel's avatar

Mariano Miguel · 4 weeks ago

Anyone who has tried putting together a design system knows that creating a cohesive color palette that looks great but still promotes accessible color pairings, supports multiple themes, and endures over time is a nightmare.

There are many ways to it, but I'm going to show you a simple method that will guarantee you'll pass WCAG's AA standards color-wise pretty much every time.

A primer on accessibility requirements

The whole premise of this article is to provide you with a method to pass accessibility guidelines. This will effectively limit your choices and make the process more complex. You may also have to sacrifice some of the trendy low-contrast pairings to make your palette accessible. This is still a small price to pay for enabling a wider range of users to use your product.

Here's what you'll need to pass AA:

  • A contrast ratio of at least 4:5:1 for any piece of text lower than 24px. This includes text inside UI components.
  • A contrast ratio of at least 3:1 for text that's at least 24px or 19px + bold.
  • A contrast ratio of at least 3:1 against the background for the boundaries or background colors of any UI elements (e.g: a text input's border).
  • Default, focus, hover, and active states that follow the rules above.

Regarding the rule about element boundaries, you can skip it if:

  • The element is inactive (e.g: a disabled button).
  • You can identify the element from its context or content alone (e.g: a button that reads "Submit your message"). Note that in this case, text still needs to meet the contrast criteria.

The magic number method

I first found out about this method when I came across the U.S. Web Design System (USWDS). They built a color-grade system that goes from 5 to 90 based on relative luminance, where each grade conforms to a specific range of values:

Grade Minimum luminance Maximum luminance
0 1.000 1.000
5 0.850 0.930
10 0.750 0.820
20 0.500 0.650
30 0.350 0.450
40 0.250 0.300
50 0.175 0.183
60 0.100 0.125
70 0.050 0.070
80 0.020 0.040
90 0.005 0.015
100 0.000 0.000

The difference in grade between any two colors is called the "magic number" (e.g: the magic number between red-90 and red-30 is 50). While this may seem complex at first sight, the beauty of the system lies in its simplicity:

  • A magic number of 40+ results in WCAG 2.0 AA Large Text contrast, so it's great for text over 24px or border colors.
  • A magic number of 50+ results in WCAG 2.0 AA contrast, so it can be used safely everywhere.
  • Colors of grade 50 result in WCAG 2.0 AA contrast against both pure white (#FFFFFF) and pure black (#000000).

The beauty of this method is that you don't have to worry about manually checking contrast ratios when pairing between different colors. As long as your target magic number is good, an accessible pairing is guaranteed no matter which two colors you pick.

Simplifying calculations

Katie Riley from Envoy Design wrote a blog post on this exact method and came up with an amazing solution to translate the original table to work with color contrast ratios instead of abstract luminance values. Here's what that looks like:

Grade Minimum contrast vs white Maximum contrast vs white
0 1 1
5 1.07 1.17
10 1.21 1.31
20 1.5 1.91
30 2.1 2.63
40 3 3.5
50 4.51 4.67
60 6 7
70 8.75 10.5
80 11.67 15
90 16.15 19.1
100 21 21

Introducing the Accessible Color Scale Generator

You could definitely grab the values from the table, pick a starting point, and then modify the color's HSL values to fit the contrast scale. However, I've automated the entire process into a little app that you can use to generate accessible shades for every color in your system: the accessible color scale generator.

All you need to do is pick a starting color, and the system will automatically create the rest of the colors for you. The tool will also provide you with alternatives for each grade, going from less to more saturated colors.

A screenshot of the accessible color scale generator

The tool will also build a dark-mode scale for you. We keep variable names consistent with the light-mode scale, so you can easily switch between the two.

Once you're ready, you can copy your scale as a simple text list, JSON, or CSS variables. Repeat the process for your brand, secondary, and interface colors, and you got yourself an accessible color system!

Liked this post?

Get my best advice on front-end development & design systems straight into your inbox.