Calculating contrasting colours in javascript

georged picture georged · Mar 11, 2009 · Viewed 9.2k times · Source

On one of pages we're currently working on users can change the background of the text displayed.

We would like to automatically alter the foreground colour to maintain reasonable contrast of the text.

We would also prefer the colour range to be discretionary. For example, if background is changing from white to black in 255 increments, we don't want to see 255 shades of foreground colour. In this scenario, perhaps 2 to 4, just to maintain reasonable contrast.

Any UI/design/colour specialists/painters out there to whip out the formula?

Answer

enigment picture enigment · Jun 28, 2011

Basing your black-white decision off of luma works pretty well for me. Luma is a weighted sum of the R, G, and B values, adjusted for human perception of relative brightness, apparently common in video applications. The official definition of luma has changed over time, with different weightings; see here: http://en.wikipedia.org/wiki/Luma_(video). I got the best results using the Rec. 709 version, as in the code below. A black-white threshold of maybe 165 seems good.

function contrastingColor(color)
{
    return (luma(color) >= 165) ? '000' : 'fff';
}
function luma(color) // color can be a hx string or an array of RGB values 0-255
{
    var rgb = (typeof color === 'string') ? hexToRGBArray(color) : color;
    return (0.2126 * rgb[0]) + (0.7152 * rgb[1]) + (0.0722 * rgb[2]); // SMPTE C, Rec. 709 weightings
}
function hexToRGBArray(color)
{
    if (color.length === 3)
        color = color.charAt(0) + color.charAt(0) + color.charAt(1) + color.charAt(1) + color.charAt(2) + color.charAt(2);
    else if (color.length !== 6)
        throw('Invalid hex color: ' + color);
    var rgb = [];
    for (var i = 0; i <= 2; i++)
        rgb[i] = parseInt(color.substr(i * 2, 2), 16);
    return rgb;
}