Given a random background color, how can you determine a different color that would be pleasant to read on top of that background?
October 28, 2010 8:02 PM   Subscribe

I want to take a random color, and from it, generate a few other colors that are guaranteed to be legible if the first color is used as a background.

Rules like, increase brightness by X percent, looping back to 0 if it passes the maximum allowed value, and you will wind up with a different shade of the same color that will always be legible.

Or perhaps different ranges of hue, saturation, and brightness require slightly different algorithms.

Practical experiments will have to wait for the weekend. In the meantime, if someone's already done the legwork, I wouldn't mind saving some time. Is there some aspect of color theory, or an already existing guide, that covers this ground?

It doesn't have to be super-pretty, just legible. Weird primary color intensity stuff wouldn't really be okay, though.
posted by jsturgill to Media & Arts (9 answers total) 3 users marked this as a favorite
Err, in case it's not clear, I want the derived colors to be legible when used as the color of a passage of text on top of the background.
posted by jsturgill at 8:03 PM on October 28, 2010

To keep it monochromatic, you can do something like this:

textBrightness = background.brightness - 40;
if textBrightness < 0{
textBrightness += 100;
text = colorFromHSB(background.hue, background.saturation, textBrightness);

If you'd like to mix it up, complementary colors are a good place to start:

textHue = background.hue - 180;
if textHue < 0{
textHue += 360;
text = colorFromHSB(textHue, background.saturation, background.brightness);

You can do a similar thing for triad colors, but replace 180 with 120.
posted by the jam at 8:32 PM on October 28, 2010

In R, you have mean and col2rgb functions to do something monochromatic, like this:

setTextContrastColor <- function(color)
  ifelse( mean(col2rgb(color)) < 127, "white", "black" )

An equivalent function in another language would simply take the arithmetic mean of 8-bit red, green and blue values for a given color.
posted by Blazecock Pileon at 9:42 PM on October 28, 2010

Not a direct answer to your question, but you might find some inspiration or ideas in color scheme generators.
posted by Dr Dracator at 11:09 PM on October 28, 2010

i did a bit of googling, found a link that answers your question:

10 colour contrast checking tools to improve the accessibility of your design
I’ve become so accustomed to checking the contrast of any designs I create or implement that I sort of take it for granted that everybody does. Apparently this is not the case, so I figured it would be nice to be able to refer people to a list of various tools that help you check colour contrast. Hence this article.
Apprently the World Wide Web Consortium (W3C) Web Content Accessibility Guidelines (WCAG) v2.0 suggest a 7:1 contrast ratio between text and background colours, with accompanying luminosity equations for getting this right (guideline G17). But the WCAG v1.0 suggests a different set of RGB-based equations here.

Whew! I think you can stick to the tools provided, no?
posted by asymptotic at 2:14 AM on October 29, 2010 [1 favorite]

[As part of that guarantee, we're assuming that you're assuming normal color vision, right? If you want to factor in any flavor(s) of color-blindness, the answers are necessarily going to get very different.]

As for the actual generation end of this, a little digging should turn up utility libraries for any given programming language to do the required calculations, such as Color::Calc for Perl. I doubt any of them are going to have a "make_readable" function, of course, but they'll save you work once you get some working values, like from Asymptotic's links.
posted by Su at 2:37 AM on October 29, 2010

Great stuff! Thanks.
posted by jsturgill at 6:58 AM on October 29, 2010

I wrote a post on this a few months back: Calculating Color Contrast for Legible Text in Ruby. It's in Ruby (per the title of the post), and is aimed at hexadecimal background colors, but I explain all of the logic behind the process, so you could port it to an alternate language easily. It's just as the jam and Blazecock Pileon noted above.

Here's the relevant code:

def convert_to_brightness_value(background_hex_color)
(background_hex_color.scan(/../).map {|color| color.hex}).sum

def contrasting_text_color(background_hex_color)
convert_to_brightness_value(background_hex_color) > 382.5 ? '#000' : '#fff'

(and that can be simplified to ...)

def contrasting_text_color(background_hex_color)
(background_hex_color.scan(/../).map {|color| color.hex}).sum > 382.5 ? '#000' : '#fff'

And you'd run it with the code
posted by Alt F4 at 7:11 AM on October 29, 2010

Thanks for the feedback. I decided to convert the background from RGB to HSL and then modify the S and the L to generate new colors (the H, too, for links) that are certain to contrast with the original.

I used PHP and implemented these algorithms for the conversion between RGB and HSL color spaces.

Works great, and you helped me get there.
posted by jsturgill at 1:00 PM on October 31, 2010

« Older Why does my heart feel so bad?   |   What do I ask a graduate program when I don't... Newer »
This thread is closed to new comments.