Designing an accessible color scheme, again

Katie Riley
Dec 15, 2020 · 9 min read

In early 2019, I wrote a post about designing an accessible color scheme for Envoy’s web dashboard with specific techniques I used to create various shades of all the colors we needed to build our UI.

Since then, Envoy has been on quite a wild ride. In 2020, we launched four new products (Envoy Mobile, Rooms, Protect, and Desks) and also went through a major rebrand.

We’ve been moving quickly to ensure our customers can return to work safely, but in terms of color accessibility, we backslid a bit.

So here is that story and what we did about it, including brand new techniques to help you build an accessible color scheme, whether it’s the first time around or not 😁

What happened

Image for post
Image for post

Long story short, we went through a rebrand and our brand colors changed. We love our new palette—a lot of thought and care went into choosing it (shoutout Kelly and Amy!). We were so excited that we quickly swapped some of the old product colors for the new brand colors with the goal of rolling out the new brand inside the product.

What we realized a little bit too late, however, was that brand color palettes and product color palettes are two very different things.

Not all of the brand colors were WCAG AA compliant for the smaller text common on Envoy’s web dashboard, even if those same colors were just fine for the larger copy on Envoy’s marketing website.

We also needed more colors than those included in the brand palette to represent common product states like warning, error, and success. In our excitement to roll out the new brand, some new colors for these states were chosen, but most of them were not accessible, and after a few months we realized that some shades didn’t feel like they fit into the new brand palette all that well.

Image for post
Image for post
Our “information” (blue) color didn’t mesh with our new brand palette’s emphasis on purple-toned blues, and our “error” (yellow) color didn’t fit into the brand palette, either.

We realized we needed to go back to the drawing board and build on top of our beautiful brand palette to create an expanded color system for our products that would ensure accessible content and provide flexibility for all our states and common components. We had work to do!

How we built a new, bigger, more accessible system

Last time around, I created four shades of each main UI color, and six shades of grey.

Image for post
Image for post

I built all the colors on top of a white background and chose shades greater than or equal to common accessibility contrast ratio breakpoints of 7:1, 4.5:1, and 3:1. I also included a lighter shade to use as a background color with ~1.1:1 contrast.

This system ensured that text would be accessible on top of a white background, which is the majority of Envoy’s dashboard UI.

But over time, we realized that when we stacked colors in the system on top of each other, we weren’t able to achieve those contrast ratio breakpoints.

Image for post
Image for post
This banner wasn’t accessible — we didn’t have enough colors defined in the “warning” color family

This time around, I knew I wanted to create more shades of each color to provide more flexibility in how elements of different colors could be combined in components and still maintain accessibility.

My breakthrough came when I read about the techniques used by the U.S. government web design system (USWDS), a source I often turn to for great examples of how to build accessibly.

They created a genius system to generate color families made up of 10 “grades” or shades of each color, numbered 5 through 90 (white is always grade 0 and black is grade 100).

This system guarantees accessibility with it’s “magic number” method: if you stack one grade over another, as long as there is…

  • 50 points difference between two color grades ensures greater than 4.5:1 contrast
  • 40 points difference between two color grades ensures greater than 3:1 contrast

The USWDS documentation lays out exactly how to build color families this way in a table that shows the precise relative luminance values each grade must fall between to make the magic number system work.

Image for post
Image for post

This is a great resource, but if you’re anything like me, you also might not have ever heard of relative luminance. Don’t worry, I got you.

While it may be oversimplifying, think of luminance values as how bright a color is from 0 to 1. White is the brightest color (1) and black is the darkest color (0). A larger number equals a lighter color.

Knowing this, the table above starts to make more sense; for example, Grade 5’s luminance can’t be any darker than 0.850 or any lighter than 0.930. Those luminance values are quite close to 1, so we can visualize that Grade 5 is very close to white, a very light color.

I also learned that the formula for calculating contrast ratios relies on these luminance values:

(L1 + 0.05) / (L2 + 0.05)L1: the relative luminance of the lighter of the colors
L2: the relative luminance of the darker of the colors

Because I wasn’t as familiar working with luminance values, and I had a hard time finding a tool to quickly translate a hex value into a luminance value, I decided I would instead translate the USWDS table into contrast ratios (as compared to white) using the formula above.

Grade 5’s luminance value can be no darker than 0.850 and no lighter than 0.930What contrast ratio would a color with a luminance of 0.850 have against a white background?We know the formula for contrast ratio is lighter divided by darkerWe know that white has a luminance of 1Applying these known values to the contrast ratio formula, you get:(1 + 0.05) / (0.850 + 0.05) = 1.17:1Repeat for 0.930(1 + 0.05) / (0.930 + 0.05) = 1.07:1Solved: Grade 5 can be no lighter than 1.07:1 against a white background and no darker than 1.17:1

This helped me produce a resource in terms I could understand faster, and allowed me to use existing Figma plugins to more quickly calculate if my color was in range.

Image for post
Image for post

Following the table above could absolutely empower you to quickly create color families. In Figma, it’s as easy as firing up Contrast, drawing some rectangles, and adjusting HSL values until each color falls into the right range of contrast values (and you like the way it looks).

Image for post
Image for post

You can absolutely stop reading here, follow those ranges and create amazing and accessible color schemes.

I will only give you one more pro tip to do this in the browser version of Figma, or change your color space in desktop Figma, because there can be substantial differences in color between the two, and you’ll likely want to know what the colors will look like in the browser before committing to them.

But if you’d like to continue reading, I will show you how you can adjust the USWDS ranges to make them lighter or darker according to your preferences. It’s gonna get mathematical!

Image for post
Image for post

I personally found that the USWDS ranges, as written, produced color schemes that were a bit darker for Grades 60+ than I wanted; I wanted to get as much vibrancy as possible even from my darker shades.

Using the same formula for calculating contrast ratio, I set out to make some adjustments.

I started with Grade 60. In the USWDS table, Grade 60 had a contrast ratio range of 6:1–7:1. I wanted to lighten up the low end of the range to 5.5:1.

Since there’s 40 points difference between Grade 60 and Grade 100, I knew that Grade 60 would need to have at least 3:1 contrast against black (Grade 100).

What’s the maximum contrast allowed for Grade 60 to that can still achieve 3:1 vs. black?• Formula: (L1 + 0.05) / (L2 + 0.05) = contrast [lighter divided by darker]
• Black has a luminance of 0
x / 0.05 = 3
3 * 0.05 = 0.15
0.15 - 0.05 = 0.1 (maximum luminance value for Grade 60)
Convert that luminance value back into contrast against white:(1 + 0.05) / (0.1 + 0.05)
1.05 / 0.15 = 7:1 (maximum contrast value for Grade 60)

So I must leave the upper bound of the range the same: 7:1.

Grade 60 has a 50 point difference with Grade 10, so what’s the darkest Grade 10 can be to still achieve 4.5:1 versus Grade 60?

Assume the lightest Grade 60 can be is 5.5:1What's the luminance of a color with a contrast of 5.5:1 against white? (manipulate the same formula)1.05 / 5.5 = 0.191 - 0.05 = 0.141Solve for Grade 10 luminance:x / 0.191 = 4.5
0.191 * 4.5 = 0.86 - 0.05 = 0.81 (maximum luminance value for Grade 10)
Convert that luminance value back into contrast against white:1.05 / 0.86 = 1.221:1 (maximum contrast value for Grade 10; can't be darker than this)

And finally, Grade 60 has a 40 point difference with Grade 20.

1.05 / 5.5 = 0.191
0.191 * 3 = 0.573
1.05 / 0.573 = 1.83:1 (maximum contrast value for Grade 20; can’t be darker than this)

Essentially, by using the formula for calculating contrast ratio and the concept of the magic number, you can continue to make any adjustments you’d like to the grade ranges. I adjusted most of them just slightly, ending up with this table of values:

Image for post
Image for post
* A firm limit; the system will break if you go beyond this value. Unmarked values could be exceeded slightly, if necessary for aesthetics or brand, without breaking the system.

I think these changes were noticeably helpful to make the darkest few grades more vibrant and less like “almost black” shades, which works better for our product.

Image for post
Image for post
USWDS ranges (above) versus my lightened ranges (below)

I will note, though, that USWDS’s system supports level AAA compliance with a magic number of 70, which I did not test my adjusted system against, so if you are aiming for a higher accessibility standard, you may want a darker range of colors.

After lots of math and hours of tiny HSL adjustments, this is where I ended up:

Image for post
Image for post

The absolute best thing about this system is its flexibility and “stackability”—as long as the magic number is met, you can stack any color over any other color and accessibility is guaranteed.

Image for post
Image for post

This new system includes all our brand colors marked at their appropriate grade, so all brand colors can be used in the product accessibly, as long as the magic number is met.

You’ll notice that not all grades are defined. For our brand color (red) we decided to only create a few adjusted values to meet accessibility breakpoints and not to create lighter shades which won’t look visually similar to our brand color.

For our chartreuse, orange, and green colors, we use those rarely for warning, error, and success states, so darker shades weren’t necessary at this point—however, it’d be easy enough to go back later and define more grades.

Overall, our new color system gives our designers incredible flexibility in building new components, and guarantees that our products are accessible. What more could you ask from a color scheme? 🌈

Have thoughts on this topic? Sound off in the comments or chat to me on Twitter!

Thanks for reading! Be sure to visit and subscribe to get notified when we publish something new. Or check out my previous article, How to build management skills before you’re a manager

Envoy Design

Stories and ideas from designers that challenge the…

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store