There are certain things that every nerd reinvents from scratch at some point in their life, and text editor color schemes are close to the top of that list.

My contribution to this discussion about deeply personal opinions aims to explore the purpose of color as a tool for communication, not aesthetics. If you want your code to look like a rainbow—which there’s nothing wrong with—you probably won’t like the approach I present below. But for those who simply want their code to be maximally legible, this might be for you.

To start off, let’s take a look at the color scheme I came up with:

/**
* Returns the factorial of a non-negative integer. Throws if the
* input is negative or not an integer.
*
* A factorial of a number N is the product of all positive integers
* less than or equal to N. By definition, the factorial of 0 is 1.
*/

export function factorial(num: number, acc = 1) {
if (num < 0 || !Number.isInteger(num))
throw new RangeError(
"Can't calculate factorial for non-integer or negative number",
);

if (num <= 1) return 1;

// Passing the second param makes this a tail call
return factorial(num - 1, acc * num);
}

And for reference, here’s the same code in the default syntax highlighting theme from Astro, the static site generator I’m using:

/**
 * Returns the factorial of a non-negative integer. Throws if the
 * input is negative or not an integer.
 *
 * A factorial of a number N is the product of all positive integers
 * less than or equal to N. By definition, the factorial of 0 is 1.
 */
export function factorial(num: number, acc = 1) {
	if (num < 0 || !Number.isInteger(num))
		throw new RangeError(
			"Can't calculate factorial for non-integer or negative number",
		);

	if (num <= 1) return 1;

	// Passing the second param makes this a tail call
	return factorial(num - 1, acc * num);
}

It’s immediately obvious how much more colorful Astro makes the code. And it’s not just Astro. Take a moment to look through VS Code Themes, a website that showcases some of the most popular themes for VS Code. All of the most popular themes are extremely colorful—most of the text on the screen is in a non-neutral color, and in many of the themes, you won’t find any pure black or white at all.

As coders, we have collectively gotten used to the expectation that wherever we see code, it’s presented in a wide assortment of colors. So why would less color be better?

Whenever you go to your local electronics store (or Costco), you’ll see that all of the TVs on display have their colors tuned to be extremely bright and vivid. This is great for grabbing your attention and making you think that the TV is high quality, but when you take the TV home, dim the lights, and watch a movie on it, those same settings that made it pop in the store will now strain your eyes and look unnatural.

I think the same thing happens with color schemes. A large, well-curated color palette is nice to glance at, but I think these large palettes are actually bad for legibility. In order to read text that switches between so many colors, your brain has to work extra hard to compensate. Sure, the colors are communicating something about what kind of thing a word or symbol is, but with the ultra-fine granularity of color distinctions, I’m not sure that the average coder understands what all the colors are supposed to mean. If the information density of colors on the screen is too low, they aren’t worth the cognitive overhead of processing them.

My approach to color is that a large proportion of the text on screen should be a “normal,” neutral color: black in light mode, white in dark mode. Any other use of color should communicate something important, and the meaning of the color should be instantly obvious.

With this in mind, I’ve found that the most useful number of text colors to have is three:

  1. A bright, saturated accent color for comments
  2. A dimmed gray for language constants, keywords, operators, punctuation, and types
  3. White or black for everything else

One great thing about this three color system is that it’s extremely flexible. Because only one of the three colors is non-neutral, the user can set the accent color to anything they like without altering the balance of the color scheme. For the purposes of this post, I’m simply using the link color as the accent color, but it really can be any color at all, as long as it looks sufficiently distinct from the other colors.

So with all of this focus on the accent color, you may ask, why is it specially reserved only for comments? Comments aren’t real code! Don’t you want comments to fade into the background and get out of your way?

Many themes de-emphasize comments to the point where they are barely visible. I think this is exactly the wrong approach. Comments are where you’re supposed to give useful context that can’t otherwise be encoded into the program itself. They answer questions such as “What are the limitations and caveats of an API?” and “Why is this line of code written in a complicated way when it looks like a simpler way would suffice?”

If you use low contrast to obscure comments, you’re communicating that they’re unimportant, thus discouraging people from both reading and writing this crucial kind of documentation. Rather, by presenting comments as the most important snippets of your code through brightness and saturation, you draw people’s attention to them as important guides to pay attention to and wrestle with.

As for the second category, the long list of scopes that are presented with low (but not unreadable) contrast, all of these fall into one of a few categories:

I experimented with giving strings and numeric literals a secondary accent color, and ultimately decided that this wasn’t necessary—it’s more important for me to keep the number of distinct colors low than use a distinct color to tell where a string starts and ends. I expect most people to disagree with me on this point, so to be clear, this is a purely matter of personal preference rather than principle.

With such a low limit on the number of text colors, what happens to the distinctions that aren’t made by color?

It turns out that programming languages, like natural languages, all contain rhythms and structures that help your brain parse large amounts of text at once without having to look directly at every word individually. Just like you don’t need every other word to be a different color in order to read this sentence, having fewer colors doesn’t make it difficult to read code, either.

Plus, we have a plethora of tools in addition to color to help us evaluate context. Language servers make sense of references within a codebase. Linters flag when something doesn’t look right. Bracket highlighters help you find the boundaries of the context you’re in.

Lastly, I want to talk about the issue of maximizing contrast. In Practical Typography, one of the inspirations for this blog, Matthew Butterick states:

Consider making your text dark gray rather than black. Unlike a piece of paper—which reflects ambient light—a computer screen projects its own light and tends to have more severe contrast. Therefore, on screen, dark-gray text can be more comfortable to read than black text. That’s why many digital-book readers let you reduce the screen brightness or change the text color.

When it comes to productivity, I disagree with this point. I say, let the user decide. If it looks too harsh, they can just turn down their screen brightness. But on the occasion where they need every smidgen of contrast they can get, like when working outside on a sunny day, I don’t think it’s my place to tell someone they can’t take full advantage of their 1,000+ nit HDR display.

In addition, this is an accessibility concern, as grayed out screens with low-contrast text are useless to blind and low-vision people. And coding at a computer frequently for long periods of time increases our chance of joining this group later in life, so even for those with perfect vision today, this concern may not be too far from your reality.

That’s all I have to share about my approach to syntax highlighting—a minimal, monochrome high-contrast color scheme with a neutral body color and comments highlighted in a saturated accent color. If you’re interested in trying this kind of color scheme in your own text editor, check out my Nuclear Summer and Nuclear Winter themes for Sublime Text. I haven’t decided if I like these enough to submit them to Package Control, so to try these out you’ll have to manually download the files and place them in the Packages/Themes/ folder of your Sublime Text preferences.

Published on