Colors for Programmers
Since this topic has come up a few times in conversation, recently, I assume that people (especially software developers) need better information.
As a quick note before I get started, a small amount of this content was grabbed from my Quora answer on What are ways to become a web developer/designer for someone working full-time in a different field?, which I originally answered on Saturday, May 3rd, 2014. I donât use much, since that was an unrelated topic, and it has all been adapted, but if you want to dig into that career end of things, you might want to give that a quick read, too.
I somehow end up involved in a lot of projects where a design needs a new color, and it seems like a lot of peopleâdevelopers, especially, but not exclusivelyâare terrified to work with color. But, hereâs the thing: Itâs possible to fake your way through most decisions like this with math.
The obstacle, though, is that the industry mostly operates on the RGB color model, which is terrible for showing relationships. It works well from a display standpoint, because most humans physically see the world through sensors detecting red, green, and blue light. However, there are at least two confounding factors.
First, our brain obviously reinterprets the physical input in a way that doesnât match reality. An important example of this is that visible colors are transmitted as photons with wavelengths from about 380 (violet) to 740 (red) nanometers. However, despite red and violet being as far apart in the spectrum as possible, we see those two colors to be as similar as yellow (580 nm) is to green (530 nm).
The other big problem is thatâsurely related to the brain lying to youâas youâve surely seen if youâve tried to pick a color off a single on-screen palette, is that RGB color spaces feel strangely asymmetrical, with reds and purples seeming to dominate the spectrum.
Something similar goes for the CMY color model, commonly used in printing, with the most recognizable difference being that two of the three component colors (cyan and magenta) arenât generally a part of the natural world.
All that is to say that, if I present a pair of colors that we agree look nice togetherâletâs say #e27d60 and #085dcb as shown to the right, for the sake of the exampleâand then ask for a third color that might work, finding that third color in the RGB space is a matter of trial and error or âtaste.â Give it a shot. Iâll wait. And no, âgrayâ isnât a legitimate answer, since that has almost certainly already been taken. Nice try, thoughâŚ
OK, so what can we do instead?
Hue Can Do It!
The biggest change that we need to make is to describe colors based on how they look, rather than how they can be broken down into components. The relevant broad terms, there, are hue, colorfulness, and lightness. Lightness talks about how closely the color resembles black or white. Colorfulness deals with how closely the color resembles a gray of some lightness value. And hue involves how well the color can be described as a common color, such as red, blue, or yellow.
If every color in an image is the sameâwithin some tolerance, of courseâhue, thatâs a monochrome image. If we change the colorfulness and lightness together, weâre creating a shade (mixing the color with black) or tint (mixing the color with white), because those change the lightness while reducing the colorfulness. If we change the colorfulness without the lightness, weâre adding or removing a neutral gray. I canât find a term for changing the lightness without changing the colorfulness, but thatâs what you generally see in a âmonochrome color scheme.â
The hue, as mentioned, is a number that gives a sense of how we would describe a color.
Hue | Color |
---|---|
0° | Red |
30° | Orange |
60° | Yellow |
120° | Green |
180° | Cyan |
240° | Blue |
270° | Violet |
300° | Magenta |
360° | Red, Again |
Thatâs not quite how we imagine a rainbowâcyan and magenta seem to take up an oddly large amount of space for colors we donât ordinarily seeâbut itâs pretty close and red does meet at both ends of the spectrum.
Letâs look at our colors above, again, this time in terms of hue, saturation (the computer-y term for colorfulness), and lightness.
RGB | Hue | Saturation | Lightness |
---|---|---|---|
#e27d60 | 13.4° | 69.1% | 63.1% |
#085dcb | 213.8° | 92.4% | 41.4% |
I hope thatâs a bit more enlightening. The first color is a red-orange or a rust thatâs somewhat dull. The second is a bold but medium-lightness cyanish-blue. Right off the top, I think itâs obvious that this is a useful notation, just because it gives a better intuition for what the color looks like, if you can remember most of that table above. And, yâknow, you can just look it up quickly; no shame in that.
Have you ever heard a designer complain that the boss or client âwould like the blue to be bluerâ? They might want the hue closer to 240°, but more likely is that they want to increase the saturation. They want the color to be âsofterâ? They probably mean bringing the lightness closer to its neighboring colors.
Anyway, letâs pick our third color! Iâm going to assume that the orange color is being used as a background, since otherwise weâre guessing. The most naive color we can pick takes the difference between each of the three values and swings them around the other side of our background. SoâŚ
Color | Hue | Saturation | Lightness |
---|---|---|---|
Orange | 13.4° | 69.1% | 63.1% |
Blue | 213.8° | 92.4% | 41.4% |
Difference | 200.4° | 23.3% | -21.7% |
Orange â Î | 173.0° | 45.8% | 84.8 |
That gives us our new color (#c6eae6, if you want to play along in RGB), calculated to look as different from the orange as the blue is, sounds likeâbased on the middle-of-the-road saturation and high lightnessâa washed-out cyan. Yes, the blue and cyan sound close, but this isnât necessarily bad. In fact, refer to the example to the right; the cyan is definitely not as bold a part of the mix as the other two, but itâs distinctive and doesnât clash with either color. Success!
And, of course, keep in mind that the monochrome discussion applies here, too: Adjust the lightness and saturation of the colors to produce supplemental colors. Iâm just mechanically coming up with the non-hue values because Iâm more confident in them, but a bolder or darker cyan is almost certainly a decent choice, too.
Thereâs also a good chance we can take intermediate colors, too. Letâs say 93.2° hue, 57.45% saturation, 73.95% lightness? Thatâs a faded yellow-green (#b9e396), which you can draw on the sample on your own time.
This approach is referred to as choosing âadjacent colors,â even though the colors are pretty far apart. Itâs what I suggested earlier, that you have one âmainâ color and then one color to either side, the same angle away. Youâll occasionally hear the term âtriadicâ used in cases like this, where the main color is farâmore than 90°âfrom its neighbors.
Oh, and thereâs one other important color to consider: The complementary color. Not âcompliment,â like free things that say nice things about youâlook up the joke about âcomplimentary peanutsâ before pointing out the grammar mistakeâbut the opposite of a thing that makes it whole. Complementary colors are those whose hues are 180° apart from each other, so the complement to our rusty orange is 193.4° (#60c5e2), which is sort of a sky blue, and youâll notice that itâs right between the bold blue and the cyan.
Generally speaking, complementary colors are too bold to use as more than an occasional accent or one color has a saturation or lightness that makes it feel muted. But that accent generally works inside any color scheme.
Notice that triadic colors are adjacent to the complementary color.
In addition to adjacent/triadic schemes, youâll also generally see reference to âtetradicâ color choices. This is sort of a mix of adjacent and triadic, where the main color and its complement each get an adjacent âpartner.â Five colors generally get a spread that looks like triadic, but taking adjacent colors of the non-primary. Likewise, six colors split the primary color to two adjacent colors. If you need more than six colors with all of saturation and lightness values available, your vision might be too complicated.
Anyway, if the rusty orange is our main color, know the sky blue is complementary, and we have the bold blue as our secondary color, then the fourth color should be the bold blueâs complement, 33.8° hue, 92.4% saturation, and 41.4% lightness (#cb7608), which is a brownish-orange. That doesnât look so great, but itâs more because the orange colors are too similar.
Letâs take a more random example, and when I say random, I mean âlet http://randomcolour.com pick the main color.â In this case, it gave me #8d1450, or 330.2° hue, 85.8% saturation, and 55.3% lightness, a dark reddish-magenta. We know the complementary hue is 330.2° - 180° = 150.2°, somewhere between green and cyan. Now we need a random angle, something less than 90° but larger than the 20° that felt too close to eyeball. Generating a random number in that range gives me 37°. So, 330.2 + 37 = 367.2° (or 7.2°, since this is a circle) and 150.2 + 37 = 187.2°.
(If you look at the table of hues above, you might notice that an angle of 30° or 60° is probably going to give recognizable results.
Is this a color scheme thatâs going to win awards? Probably not. The red looks pretty muddy against the purple, but the other combinations work well enough to function (especially with black, white, and grays added to the mix), itâs not jarring (just invisible), and the red and cyan could almost certainly stand to be lightened instead of leaving all the saturation and lightness values the same. So, Iâd call that a success.
If you have a keen eye (or downloaded the stylesheet to check), you should notice that my website uses a triadic color scheme, the background color being yellow, headers being red, and text in blue, with variants being steps up and down in lightness.
Does That Color Have a Name?
So, hereâs a related question withâŚyes, obviously with the same answer: Given an arbitrary color, can we find the closest color with an official name?
As it turns out, I created a tool to solve this in Go, back in 2016, mostly to experiment with the language. The hardest part of solving the problem was getting the list of named colors, which I just stripped out of Wikipedia.
The program does what you would probably expect, at this point: It converts the RGB values to HSL (or HSV, which is mostly interchangeable) values and then calculates the distance between the input and all the colors to find the nearest.
I recommend trying the same thingâyou can adapt the conversion algorithm/formula from my code or this answer on Stack Overflowâand comparing the results to the nearest color in RGB space (that is, the color with the nearest red, green, and blue intensities) to see which finds a better match. It might be interesting to try to find a color that matches better using the RGB distance.
Contrast
An important aspect of what makes a good color scheme, beyond just the colors looking acceptable next to each other. The World-Wide Web Consortium suggests calculating contrast as (approximately) the ratio of luminances, whichâŚOK, this is a little intricate.
- Take each of the three color components (R, G, and B) as fractions between zero and one (i.e., the integer á 255);
- For values less than or equal to 0.03928, divide by 12.92;
- For all other valuesâŚ
- Add 0.055,
- Divide by 1.055, and
- Raise to the 2.4 power;
- Sum as 0.2126 â R + 0.7152 â G + 0.0722 â B.
This Stack Overflow answer converts that mess to fairly straightforward JavaScript.
function luminance(r, g, b) {
var a = [r, g, b].map(function (v) {
v /= 255;
return v <= 0.03928
? v / 12.92
: Math.pow( (v + 0.055) / 1.055, 2.4 );
});
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
}
function contrast(rgb1, rgb2) {
var lum1 = luminance(rgb1[0], rgb1[1], rgb1[2]);
var lum2 = luminance(rgb2[0], rgb2[1], rgb2[2]);
var brightest = Math.max(lum1, lum2);
var darkest = Math.min(lum1, lum2);
return (brightest + 0.05)
/ (darkest + 0.05);
}
If the results are better than 50% for each pair of colors in use, then the colors are probably readable against each other. Personally, I find it nice that this is something that can quickly work for user-defined color schemesâproviding feedback without much overheadâin addition to making it easier to know if a color scheme is usable.
Color Blindness
Closely related to ensuring contrast is validating color schemes for people with different kinds of color blindness. For example, I was once on a project where a client was using their corporate branding colors to highlight the most recent selections in a list. Our teamâs problem with fixing problems was that several people were color-blind (they still are, individually, but the team no longer existsâŚ) and so couldnât see much difference between the colors they gave us.
Unfortunately, converting colors to simulate color blindness is non-trivial for most programming, because it requires applying matrices to the color space. Each color âchannelââone of the technical terms for one of the R, G, or B valuesâis a weighted mix of magnitudes of the three original channels.
We can do something like this, assuming that the âmatrixâ is a linear array with all the rows combined, for simpler notation.
function crop(n) {
return Math.floor(10 * (n<0 ? 0 : (n<255 ? n : 255))) / 10;
}
function AdjustChannelByMatrix(c, m, ch) {
var offsets = {
r: 0,
g: 5,
b: 10,
a: 15
};
var i0 = 0 + offsets[ch];
var i1 = 1 + offsets[ch];
var i2 = 2 + offsets[ch];
var i3 = 3 + offsets[ch];
var i4 = 4 + offsets[ch];
return crop(
c.R * m[i0] +
c.G * m[i1] +
c.B * m[i2] +
c.A * m[i3] +
m[4]
);
}
function AdjustColorByMatrix(c, m) {
return({
R: AdjustChannelByMatrix(c, m, 'r'),
G: AdjustChannelByMatrix(c, m, 'g'),
B: AdjustChannelByMatrix(c, m, 'b'),
A: AdjustChannelByMatrix(c, m, 'a')
});
};
Weâre missing the matrices, of course. The best information I can find is based on the Color Blindness Emulation project, made available under the terms of the CC0 1.0 Universal Public Domain Dedication.
{
'Normal': [
1,0,0,0,0,
0,1,0,0,0,
0,0,1,0,0,
0,0,0,1,0,
0,0,0,0,1
],
'Protanopia': [
0.567,0.433,0,0,0,
0.558,0.442,0,0,0,
0,0.242,0.758,0,0,
0,0,0,1,0,
0,0,0,0,1
],
'Protanomaly': [
0.817,0.183,0,0,0,
0.333,0.667,0,0,0,
0,0.125,0.875,0,0,
0,0,0,1,0,
0,0,0,0,1
],
'Deuteranopia': [
0.625,0.375,0,0,0,
0.7,0.3,0,0,0,
0,0.3,0.7,0,0,
0,0,0,1,0,
0,0,0,0,1
],
'Deuteranomaly': [
0.8,0.2,0,0,0,
0.258,0.742,0,0,0,
0,0.142,0.858,0,0,
0,0,0,1,0,
0,0,0,0,1
],
'Tritanopia': [
0.95,0.05,0,0,0,
0,0.433,0.567,0,0,
0,0.475,0.525,0,0,
0,0,0,1,0,
0,0,0,0,1
],
'Tritanomaly': [
0.967,0.033,0,0,0,
0,0.733,0.267,0,0,
0,0.183,0.817,0,0,
0,0,0,1,0,
0,0,0,0,1
],
'Achromatopsia': [
0.299,0.587,0.114,0,0,
0.299,0.587,0.114,0,0,
0.299,0.587,0.114,0,0,
0,0,0,1,0,
0,0,0,0,1
],
'Achromatomaly': [
0.618,0.320,0.062,0,0,
0.163,0.775,0.062,0,0,
0.163,0.320,0.516,0,0,
0,0,0,1,0,
0,0,0,0,0]
}
So, for every color scheme we generate, we actually have nine schemes to validate for usable contrast.
Putting It Together
That might sound daunting, but bear in mind that most of the joy of software is that we only need to work out (or find, as the case may be) the tedious math like this once, and we can apply that solution in bulk.
So, given what we know, we should be able to accept a primary color, angle, and geometry (adjacent, triadic, etc.), generate a color scheme, and validateâpossibly adjust, if youâre willing to have code iterate on saturation and lightnessâthe contrast of the resulting color scheme and how it will look to each of the eight kinds of people who are color-blind.
Itâs still important to visually inspect the results, of course, but Iâd call that a pretty long way to go without needing to think much about preference or taste.
HoweverâŚ
All of this should be taken as thinking about new work. If youâre working on something for a company that exists, you can usually short-cut most of this work through the simple expedient of asking someone for the companyâs branding guidelines. I mean that literally. If the company has graphic artists, their manager is probably the keeper of the document. Otherwise, Human Resources often knows where to find it, since someone there is generally responsible for job fair banners and the like.
If you donât have inside contact with the organization or are too shy to ask your colleagues for help, you can also try searching the web for the company name and âbranding guidelines.â Companies involved in a lot of partnerships or have significant media attention generally keep their expected color palette, fonts, and assorted branding assets public.
If you have a branding guide, avoid deviating from it, if you can. Adding a small amount of an accent color is usually acceptable, but generally speaking, the further you are from the text, the more likely a manager is going to reject the design.
Bonus: Some Design Links
If you need to quickly get up to speed on broader design than just color, I canât âhighly recommendâ it, because itâs a strange (and probably illegal) combination of licenses like the GPL and CC-BY-NC, but Digital Foundations discusses free software art tools, symmetry and gestalt, the grid-based Bauhaus school of design, some basic color theory (mostly definitions), image types, and so forth. Like I said, Iâm not pleased with the strange licensing, but itâs the broadest text on the topic that is designed for beginners.
More broadly, most Floss Manuals books are licensed under the GPL with the intent of distributing them with the applications they talk about. They seem to have fallen a bit out of date on the âmanualâ aspect, but theyâre still decent starting points on a lot of topics.
Not at all Free Culture (and not encouraging free software), unfortunately, but I havenât found anything nearly as useful as Butterickâs Practical Typography on the topic ofâŚwell, typography. You might also want to search for articles on âfont pairingsâ for articles with some useful advice. Throwing in âopen sourceâ wouldnât be the worst idea, if youâre trying to keep to work that can be easily shared.
Since you canât generally deal with design while ignoring user experience (unless youâre just creating a static image, which seems unlikely), again, itâs unfortunately not Free Culture, but itâs hard to find better adviceâadvice as backed by data, evenâthan Nielsen Norman Groupâs biweekly articles. I have yet to find their videos useful, but theyâve been posting fairly solid advice regularly since the early days of the web and frequently revisit their old findings to see if they still hold true. For example, they sounded the alarm on the ineffective nature of web-based advertising in the summer of 1997!
I also like 24 Ways as a source of interesting tips and advice that mostly revolve around presentation. Youâll notice that my website (including this blog) takes more than a couple of cues from one particular article. Likewise, CSS Tricks has an enormous backlog of advice, plus Snippets with quick tricks.
If all else fails, you can also just work from Googleâs Material Design guidelines. It may not be interesting, but itâs a complete, documented system thatâs familiar enough that most people wonât find a problem using your design. Alternatively, flat design might as well be âdesign for programmers,â with no borders, shadows, gradients, textures, animation and usually a limited color palette on a neutral background; Material Design branched out of a flat approach, with a small handful of depth levels and shadows.
Alternatively, if youâre working on desktop software, you canât go wrong just using your target platformâs design language. On Windows, thatâs either Aero or Fluent. On macOS, itâs Aqua. Android uses Material Design. Unfortunately, I canât find an explicit design language for any Linux distributions, most generally just having a set of guidelines that expand whenever something new is needed. But the point is that, if you use a language that your users/readers have already learned, youâll have a much easier time and many decisions will have already been made for you.
Again, though, a lot of the above information isnât entirely under a Free Culture license. If youâve seen better material on any of these counts that has been made available under a usable license (if it allows any use, optionally under conditions of attributing the author and/or sharing any derivatives, the license should qualify), please leave a comment, and Iâll update this post crediting you. Heck, Iâll even take mediocre material! The best I can find is this clunker on Wikibooks thatâŚwell, it needs a lot of love to make it into something I would feel comfortable recommending it.
Credits: The header image is Eine Innenansicht der Nasir-ol-Molk-Moschee in Schiras, Iran by Ayyoubsabawiki and is released under the Creative Commons Attribution-Share Alike 4.0 International license.
By commenting, you agree to follow the blog's Code of Conduct and that your comment is released under the same license as the rest of the blog. Or do you not like comments sections? Continue the conversation in the #entropy-arbitrage chatroom on Matrix…
Tags: techtips programming design color format math