Tip of the week #009: color variable names in CSS

Naming and using color variables is hard, but here's one way to do it.

When deciding on the colors for your project it's important to figure out if you need variables for them in the first place. If the project is small and you're working on it alone you should know that it's OK to just use the color values directly in your code, like this:

Language: css
body {
  color: #202020;
  background-color: #f2f2f2;
}

There's nothing wrong with this approach. A handful of colors is managable this way, and if you need to replace one color you could always use the "search and replace"-function in your editor. However, this can become somewhat unmanageable as the project scales.

Palettes and usage

First I declare every color in the design's palette as variables and give them names. I like to give them a proper name based on what color it is, so that it's easy to remember and work with, like this grayscale here:

Language: css
:root {
  --color-white: #FFF;
  --color-mist: #EEE;
  --color-ivory: #E6E6E6;
  --color-fog: #DDD;
  --color-stone: #787A85;
  --color-concrete: #565862;
  --color-grit: #353738;
  --color-void: #292a2d;
}

I usually come up with the names myself, but if I need inspiration I use a tool called "Name that Color", by Chirag Mehta.

I prefer this approach to naming colors blue-100 or red-500. Also, I've encountered to many scenarios where the designer introduces a new color somewhere inbetween to ranges, like between blue-400 and blue-500, making me add a new variable called blue-450 to avoid renaming everything. That's also the reason I stay away from "t-shirt sizing" variables, like s,m,l,xl,xxl etc., but that's a story for another time.

Having created my palette it's time to start using it, but not directly as property values. Here's what I mean:

Language: css
:root {
  --color-mist: #EEE;
}

.card {
  background-color: var(--color-mist); /* ❌ */
}

Instead I create usage spesific variables, either more general variables like this...

Language: css
:root {
  --color-mist: #EEE;

  --primary-bg-color: var(--color-mist);
}

.card {
  background-color: var(--primary-bg-color);
}

...or even more spesific ones like this:

Language: css
:root {
  --color-mist: #EEE;

  --card-bg-color: var(--color-mist);
}

.card {
  background-color: var(--card-bg-color);
}

If I need different themes I tend to do the latter. This gives me the opportunity to easily swap the colors of my components when viewed in diffent color themes:

Language: css
:root {
  --color-mist: #EEE;
  --color-fog: #DDD;
  --color-asphalt: #333;
  --color-void: #202020;

  /* Usage spesific color variables */
  --card-bg-color: var(--color-mist);
  --card-text-color: var(--color-void);
}

:root[data-theme="dark"] {
  --card-bg-color: var(--color-asphalt);
  --card-text-color: var(--color-fog);
}

.card {
  color: var(--card-text-color);
  background-color: var(--card-bg-color);
}

Obviously there's more to this than that, but the general idea is this: separate the palette from the usage, and it will become much simpler to change colors in the future, either by adding new colors to the palette, or changing the theme of components and layout.

And yes, if you go down this path you'll end up writing a lot of variables. If this doesn't suit you, remember that you should always take into account the scope of your project, and choose the approach that suits you the best.