18

In my Android app a user can choose the color of an item. This color is then shown in background with a text on it. I want to display the text either in black or white - depending on the background color.

Is there a formula to calculate when it is better to show a text in white and not in black? I guess I am looking for the darkness of a color and the exact value when it is more black than white.

  • 1
    This is more a question for Stack Overflow. You know how to solve a problem in UX and are now looking for how to implement it. – jazZRo Apr 23 '17 at 7:06
  • 4
    I doubt this would be well received there. I don't have a programming question. I am asking about colors. – juergen d Apr 23 '17 at 9:10
28

Yes there is a formula. I wrote an article on high contrast colours recently that charts the variation of black or white (actually off-white #f0f0f0 and off-black #101010) as the foreground colour with the highest contrast ratio, for ranges of background colours.

There is also an interactive SVG version with tooltips of the contrast ratios

The contrast ratio is calculated as (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.

The charts I created are below, along with some of my notes from the above article.

Each colour cell has a circle:

  • Solid circles: contrast ratio <= 4.5
  • Thick circles: contrast ratio > 4.5 (WCAG 2.0 AA compliant for 14 pt text)
  • Thin circles: contrast ratio > 7 (WCAG 2.0 AAA compliant for 14pt text)

In the first chart, lightness is a constant 128, while hue and saturation vary:

enter image description here

It’s interesting to see that black is generally much better than white, except in the blues and reds. There were no yellows and greens where white was better and black has a contrast ratio of over 7 for a great swathe of those yellows and greens, while white struggles to get the ratio over 7 except in the purest deep blues. The gap in the purples where black again excels is intriguing too.

In the second chart, saturation is a constant 255, while hue and lightness vary:

enter image description here

Unsurprisingly, white works on black and black works on white, but again black dominates overall except in the blues. Black dominates most against the yellows. There’s not a lot of surprises here, but it’s compelling to see the evidence laid out like this. Unlike the varying saturation, here a vast majority of the ratios get above 7 (the thin circles).

  • 2
    This is incredibly fascinating. I've always just eyeballed it, but this totally makes sense. – phyrfox Apr 23 '17 at 0:40
  • 2
    +1 I've saved this for future reference. Always just done it by eye, I believe most people get it mostly right most of the time, but this gives an intriguing insight into WHY and I'd more than happy if this was accepted as the canonical method by which to make such a decision – Darren H Apr 23 '17 at 8:54
  • Great answer. Wanted to add that if people can work in the HCL color space (designed for human color perception) instead of RGB, this problem becomes easier. The L component in HCL is the luminance mentioned here. Then the color selection workflow becomes, for example: (1) decide what contrast ratio you want, (2) pick a background color in HCL, (3) pick the min/max L value for text that meets the desired contrast ratio, (4) change H and C values for the text while not changing L, (5) translate HCL color to RGB. A lib that might help: gka.github.io/chroma.js (also baked into d3) – Chris Calo Mar 28 '18 at 16:37
5

You should choose the text color such that success criterion 1.4.3, Contrast (Minimum), of WCAG is met. It turns out that the required contrast ratio of 4.5 can be met with any choice of background color, and an algorithm to make the choice of white vs. black text is quite simple.

Step 1: Convert the input color (background in your case) to HSL. Actually, you only need the luminance (or lightness). See the definition of relative luminance in WCAG 2.0 for a formula to convert from RGB space.

Step 2: The formula for contrast ratio given in the WCAG 2.0 definition can be rearranged if we know that the text will be black (luminance = 0) or white (luminance = 1). So, let the input color's lightness be L, then:

  • If L ≥ 0.175, then black text is okay.
  • If L ≤ 0.1833, then white text is okay.

There is a small range of color where either choice would meet the contrast requirement, so using a cutoff value where the contrast ratio is equal in both cases makes sense, which occurs at 0.1791 (Wolfram alpha solution). Alternatively, you could back off slightly from using pure black and pure white, but you'd need to redo the algebra.

Note that this is a simple algebraic proof of the result obtained in the answer given by @roger-attrill. There are many more colors with lightness above 0.175 than below 0.1833, so black usually is the better choice.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.