Let’s say you’re creating a CLI tool which has to display syntax highlighted source code. You begin by choosing some colors which look nice with your chosen terminal theme:
Nice! However, who knows if it’ll still look good for people who use a theme different to yours? It seems sensible to try out the defaults, at least. Let’s start with the macOS Terminal.app default theme:
Youch! It seems fair to try the Tango themes next, since those are the default on e.g. Ubuntu:
Hmm, better, but not by much. Finally, let’s try what is likely the most popular custom terminal theme – Solarized:
Well then … Let’s take a look at each palette and investigate.
Sorcerer
In Sorcerer,
all colors are readable
on the default background
except for black
,
which is in fact darker than the background.
This is useful as the background color
for status bars and the like.
white
is the same color as
the default foreground,
and brblack
is a nice faded color.
Additionally, brwhite
is
even lighter than the foreground;
this allows for subtle emphasization
of important text
like error messages and titles.
Basic
The Basic themes are, well, horrendous.
Really owning that 90s xterm look, it seems.
bryellow
is unreadable in light mode
(check out that function name
from the code sample earlier),
while in dark mode
both blue
and brblue
are totally illegible.
That leaves us with thirteen colors we can safely use:
Tango
In my opinion
these did a lot better than
Terminal.app’s Basic themes,
but they are still far from perfect.
bryellow
is again unreadable in the light theme,
and perhaps brgreen
is
a little difficult to see,
though it’s nothing that would
stop me from using brgreen
in an application.
At this point you may have noticed
how the greyscales –
black
, brblack
, white
& brwhite
–
have remained consistent
between light and dark themes
for both Basic and Tango.
Of course,
this means that
{,br}white
is unreadable in Tango Light
(owing to the light background)
and black
is unreadable in Tango Dark
(owing to the dark background).
In other words:
forget about
that idea of mine from earlier
about using brwhite
to emphasize content.
Unless, of course,
you don’t mind if your
eminently emphasized words
are completely unreadable
for the user of your software
who deigns to use the default light theme
of A Popular Linux Distro.
On the other hand,
using brblack
to de-emphasize content
still seems fine to me.
I suppose some extra contrast
for brblack
in Tango Dark
would be nice,
but with text which is meant to be ignored
I don’t think this matters much.
And lo, but ten colors remain.
Solarized
Solarized is a curious beast. Every color in it was chosen using L*a*b*, a perceptually-uniform color space from the 1970s. (For what it’s worth, color science has progressed significantly since then; the only reason Ethan Schoonover used L*a*b* is that it’s commonly used in photography, and he used to be a professional photographer.)
Its lightnesses are perfectly symmetrical so that Solarized Light and Dark can share a set of accent colors while maintaining identical contrast. Moreover, the warm tones of the light theme and cool tones of the dark theme are complementary. (The hue gap is closer to 150° than 180° in reality. See here and here to compare hue values.)
Solarized is also incredibly popular. I have no data here, but as of the date of writing it’s the most starred theme repository on GitHub I can find. Solarized has 15.4 thousand stars at the moment, while the next-closest is Gruvbox with 11.8 thousand. Solarized is available as a plugin or sometimes even as a built-in preset in damn near every popular terminal emulator and editor on the planet.
To understand Solarized’s peculiar arrangement of the 16-color palette, we have to travel back in time to 2011 when Solarized was first released. In this dark era, terminals supporting 24-bit color didn’t exist / weren’t widespread. One option common among Vim themes at the time was to round every color to the nearest 256-color palette value. In Solarized’s case, this destroys the mathematical symmetry at the heart of the theme. (I’m not kidding, it looks awful.)
The solution – rather, hack – chosen at the time was to distill all the colors used in the Vim interface down to a palette of sixteen colors. Conveniently, Solarized’s accent colors fit nicely into the non-bright column of the 16-color palette, while Solarized’s monotones fit into the bright column. Once the user sets their terminal to use the Solarized palette, Vim can color its entire interface using only the 16-color palette and get correct color values, no clunky color approximations needed.
The downside to all this is that an application which uses any of the bright colors which Solarized co-opted for itself will look strange. Users of Solarized – and, by god, there’s so many of them – appear frequently on issue trackers asking why command-line output is inexplicably gray or even invisible as a result of CLIs using these forsaken bright colors.
Our beloved brblack
is unreadable in Solarized Dark,
so we’ll have to strike it from the table
in addition to the affected bright colors.
A sad note about bold
Far back in the past, there was no way for terminals to display bright colors. As a workaround, manufacturers (we’re talking about physical terminals here) started making all bold text bright instead of using a heavier font weight. One way or another this ended up in the default settings of many modern terminal emulators (in spite of not being in the standard), meaning that regular colorful text made bold can become bright too, depending on the user’s configuration.
Conclusion
And so, I present to you the final version of our table of acceptable colors:
Bold: ██ boldblack ██ boldbrblack ██ boldred ██ boldbrred ██ boldgreen ██ boldbrgreen ██ boldyellow ██ boldbryellow ██ boldblue ██ boldbrblue ██ boldmagenta ██ boldbrmagenta ██ boldcyan ██ boldbrcyan ██ boldwhite ██ boldbrwhite % █
Only eleven out of our thirty-two possible color settings are permissible, given that we want applications to remain readable for as many people as we can.
If you’re developing a command-line tool which will be used by anyone apart from yourself, I strongly recommend you limit your use of color to the ones I’ve identified here as being “mostly alright” and “not unreadable in a common configuration used by tons of people”.
Appendix
You probably didn’t notice, but I styled the “terminal windows” in this post to look as similar as possible to macOS Terminal.app windows through painstaking color picking and pixel counting.
The dimensions in each window’s titlebar matches as closely as I can with its actual dimensions on-screen.
The colortest
and highlight
utilities
are entirely fictional.
Terminal.app doesn’t actually provide individual access to the light and dark variants of Basic; they appear as a single theme, which switches seamlessly when the OS theme changes. As far as I know, this reactive functionality isn’t exposed to any other theme, whether pre-installed or user-created. In order to capture this, I made the terminal windows in this post react to whether the rest of the site is in light or dark mode, except for the Basic windows. They remain fixed in either light or dark mode, since in real life you’ll never see, for example, a light Basic terminal with dark window chrome.
Luna Razzaghipour
29 January 2023