I might need to present content at multiple levels depending on the distance of the observer to a display. Let's say from far away the user perceives a flat colour, but from a close distance the user needs to be able to read some text. The tricky part is the flat background colour is given/can change/I have no control over.

So far I've whipped out a really basic prototype to work out the text colour from the background colour (click to pick a random background). This is a very trivial approach: I take the hue and offset it by 90 degrees (so it's different enough) and invert the brightness in HSB color space so I get a colour that's different enough to be readable/have a decent contrast with the background.

This sometimes works:

good 1 good 2 good 3

sometimes doesn't:

bad 1 bad 2 bad 3

Is this approach good/in the good direction ? If so, how can I make this better ? If not, which direction should I follow ?

Unfortunately I don't know much about type and colour theory so any hints/tips from people with experience are very helpful. This will be displayed on a screen, not printed.

What relationships between background and foreground colours am I looking for ?

3 Answers 3


Readability is all about contrast. I'd try and determine how dark each background color is in greyscale, and if it is above a 50% grey (more dark than light), use white text, below 50% use black text. This will ensure that you have at least a 50% contrast (difference in tone) to make your text readable.

This method is a lot easier than trying to play with complimentary colors or inverting and guarantees maximum tonal contrast on any color.

  • cool, I'll give this a shot Commented Apr 16, 2013 at 16:41
  • Pretty simple and pretty effective. I've played with a few options and the brightness threshold works nicely as you can see in the updated sketch. Instructions are in the comments on the left. If I have time I might want try playing with different colour spaces (like convert to Lab* and play with the components), but for now this does the job nice and simple. Commented Apr 17, 2013 at 11:31

Here my earlier answer to essentially the same question at Game Development Stack Exchange.

To summarize, like the other answers here suggest, you should generally use either black or white, depending on which one contrasts better with the background. (Of course, if you like, giving either color a slight tint won't affect the contrast much.)

Note that, in order to correctly determine how dark or light a color appears to the user, it's not enough to just average the RGB color values (or to take the lightness / value of a HSL / HSV color). Rather, you need to account for (at least) two effects:

  1. non-linearity of the device the color is displayed on, which (for RGB colors on computer screens, at least) tends to darken midtones, and

  2. spectral sensitivity of the human eye, which, roughly speaking, causes color near the middle of the visible spectrum (green, yellow, cyan) to appear brighter than those near the edges (blue, red, purple).

The first issue can be accounted for by gamma expansion, while the second simply requires a non-uniform weighting of the R/G/B color channels. Put together, here's how to approximately calculate the perceived brightness of an RGB color, and decide whether black or white would contrast with it better:

const float gamma = 2.2;
float L = 0.2126 * pow( R, gamma )
        + 0.7152 * pow( G, gamma )
        + 0.0722 * pow( B, gamma );

boolean use_black = ( L > 0.5 );

That's assuming that R, G and B are floating-point numbers between 0.0 to 1.0. If you have e.g. integers from 0 to 255, convert them to floats and divide them by 255.

The constants in the code above are (approximately) correct for sRGB input; you can adjust them if you're working in some other color space, although the exact values don't really matter all that much: for sufficiently dark or light colors the answer will be the same anyway, while colors falling near the borderline will contrast just about equally well with either black or white anyway.

  • I was considering converting from RGB to CIE XYZ or Lab*. I might offer both options in the end. Nice answer (+1) Commented Apr 24, 2013 at 20:29

I agree with John, keep the text as much as possible black/white just to be sure, you can add a small amount of saturation to the text also and you're safe. Here is a small test:

enter image description here

View in 100% here: http://flavius.clickgarden.net/random-hsb-bg-readable-text/test-01.png Download the .ai(source) file here to play around: http://flavius.clickgarden.net/random-hsb-bg-readable-text/test.ai

  • Note how, in your examples, the black text looks OK on most of the 100% brightness/saturation colors, but really bad on the blue. That's because 100% blue only has about one tenth of the perceived brightness of, say, 100% green, which is something to take into account when choosing the text color. (See my answer for details.) Basically, you never want to use black text on a saturated blue background. Commented Apr 24, 2013 at 19:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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