If you’re like me, a programmer with no formal UI design training, you’re probably accustomed to working with colors in terms of their RGB values. And, if you’re like me, you’ve probably been frustrated by the seeming irrationality of that colorspace. For example, suppose you want to find the right foreground color for a given background to ensure high legibility. If you’re stuck in RGB-land, there’s no reliable way to get from point A to point B. If you do find a combination that works, the relationship between the two colors often seems arbitrary.
I recently learned that my singular focus on RGB is the problem, because it has no relationship to the way that the human eye perceives color. Switch to a different colorspace, like HSV (for hue, saturation, and value) and voila! Suddenly colors make sense. If you’re doing any sort of UI design, and you’re working exclusively in the RGB colorspace, you’re doing it wrong.
For legibility, use HSV
Unfortunately, I’ve found that there’s no single “best” colorspace. Some problems are better solved in one colorspace, other problems in another. When choosing a text color to maximize legibility against a given background, HSV works really well. Here’s some examples, with the foreground and background colors in both RGB and HSV:
RGB | HSV | ||||||
The quick brown fox … | 147 | 196 | 147 | 120 | 25 | 77 | Foreground |
51 | 68 | 51 | 120 | 25 | 27 | Background | |
The quick brown fox … | 110 | 127 | 127 | 180 | 13 | 50 | Foreground |
221 | 255 | 255 | 180 | 13 | 100 | Background | |
The quick brown fox … | 51 | 76 | 102 | 210 | 50 | 30 | Foreground |
102 | 153 | 204 | 210 | 50 | 80 | Background |
I could keep going, but I’m sure you see the point: in the RGB colorspace, there’s no predictable relationship between the foreground and background colors. In HSV, it’s a nice, regular pattern. That definitely appeals to the rational programmer in me. If you’re looking for a foreground color yourself, I suggest starting with a delta in value of at least 30.
For gradients, use HSL
When you’re trying to generate a color gradient, I’ve found that the best choice is HSL, for hue, saturation and lightness (note that hue and saturation here have slightly different meanings than in HSV). Here’s an example, with both RGB and HSL values:
RGB | HSL | |||||
The quick brown fox … | 51 | 149 | 204 | 56 | 60 | 50 |
71 | 160 | 209 | 56 | 60 | 55 | |
92 | 170 | 214 | 56 | 60 | 60 | |
112 | 181 | 219 | 56 | 60 | 65 | |
133 | 191 | 224 | 56 | 60 | 70 | |
153 | 202 | 230 | 56 | 60 | 75 | |
173 | 213 | 235 | 56 | 60 | 80 | |
194 | 223 | 240 | 56 | 60 | 85 | |
214 | 234 | 245 | 56 | 60 | 90 |
Again, the progression in RGB is awkward and seemingly unpredictable; the progression in HSL is simple.
Is RGB good for anything?
Obviously RGB is good for something: hardware, where colors are literally created by the combination of red, green and blue LED’s (or phosphors, if you’re old school) in varying intensities. That’s why RGB is so prevalent in graphics libraries and programming in general — the concept just bled up through the abstraction layers.
Also, keep in mind that you can convert back-and-forth between RGB and HSV, or RGB and HSL. That means that the RGB values shown above are not really as “arbitrary” as I made them out to be — but the conversions are complex, much too difficult to do in your head. So it’s much easier to work in HSV or HSL, then convert only at the end, just before you have to specify the color to the computer.
I wrote a little Tcl/Tk app that lets me play around with all three colorspaces simultaneously; you’re welcome to it here. If you want to read more about color selection, I highly recommend Choosing Colors for Data Visualization [PDF], by Maureen Stone.