Luminance functions and "is this color dark?"
Color models
If someone knows only one color model, it's probably RGB. It's a great color space for computers to represent colors, but not intuitive or useful for humans. It's especially not useful when objectively determining whether a color is dark or light.
The screenshot above shows my Chrome extension Hue Tab. I had to use a luminance formula (different from RGB or HSL) to decide whether to use black or white text on the color sample.
HSL (Hue-Saturation-Lightness)
HSL is a more intuitive color model than RGB because it describes colors by their Hue (red, yellow, green, blue, purple or anywhere in between), Saturation (color intensity), and Lightness (how bright a color is).
In HSL, lightness is calculated as the average of max(r, g, b)
and min(r, g, b)
.
In HSB, brightness is calculated as max(r, g, b)
The problem is that neither Lightness nor Brightness are a perfect representation of our sensitivity of luminance. Human eyes aren't as sensitive to colors in the purple or red regions as the greens and yellows. This is why blues seem darker than greens, even if they have the same mathematical L or B value.
Luma coefficients
To approximate human perception of lightness, we need to use a weighted arithmetic mean. This table shows the percent at which each color is weighted at for the two most common luma coefficient standards.
Weighted Method | R | G | B |
---|---|---|---|
Rec. 601 (CCIR 601) | 29.9% | 58.7% | 11.4% |
Rec. 709 | 21.26% | 71.52% | 7.22% |
Currently, the W3C recommends CCIR 601. Rec. 709 is much more commonly used in video editing.
Rec. 601 luminance function
This JavaScript function finds the luminance of a hex color using Rec. 601 coefficients.
I made the cutoff for a color to be dark at < 55% luminance because personally, I think white on a light color looks better than black on a dark color.
// uses CCIR 601 luma coefficients
// input in #RRGGBB
function isDark(hex) {
// convert hexadecimal color into decimal
var decimal = parseInt(hex.substring(1), 16);
// extract red, green, and blue components separately
var r = (decimal >> 16) & 255;
var g = (decimal >> 8) & 255;
var b = decimal & 255;
// calculate CCIR 601 luma
var lightness = (0.299*r + 0.587*g + 0.114*b) / 255;
return (lightness < 0.55);
}
Demo
Here's a demo of the isDark
function. Choose from the color picker, and it will tell you the luminance and change the text to either black or white to ensure maximum contrast.