Design System Sprint 2: One Color Palette to Rule them All

A brief introduction: I’m Marcin: a former UX manager and now co-founder and CEO at UXPin — the full stack UX design platform. In this series of posts, I’m reporting on UXPin’s journey of creating our own design system. In the first post, I discussed the fundamentals of design systems (the why? the what?). The second post was focused on creation of the interface inventory. Today, we’re going to discuss the first real battle that our newly organized Design Operations team had to go through. The battle of a unified color pattern.

So, here’s all the steps leading up to this point:

  1. We know we suffer from design inconsistency (perhaps the biggest problem in product development).
  2. We know we need to create a design system to solve the issue.
  3. Creating an interface inventory not only pointed out multiple inconsistencies we can fix relatively quickly, but also proved that building a design system is worthwhile.
  4. Soon after finishing the interface inventory, we formed a small Design Operations team (consisting of me, our Head of Design, a senior designer and a senior UI architect) to build our design system in weekly sprints.

Now we need to face the problem of our color palette.

Colors Matter

Why?

First of all, our troubles with the color palette were very easy to spot. After all, 116 variables in the definitions of colors used in the UXPin UI did seem just a bit out of the ordinary.

Building a consistent system of colors, reducing the number of used variables, and eliminating unnecessary duplicates seemed like a quick win. And so we dedicated our first sprint to fixing it once and for all.

The result of our Interface Inventory sprint — list of 116 color variables

Secondly, colors have a tremendous effect on the overall perception of a digital product.

The study The Impact of Color on Marketing (quoting after Jonathan Z. White, ‘Designing in Color’), shows that up to 90% of snap purchase decisions are based solely on the perception of colors. While purchase decisions can’t be equalized with the user experience, the study shows the significance of color to our overall cognition. Furthermore, internal relations between colors can make or break the experience. So if there’s not enough contrast between the text and background, users will have a hard time using a product. Finally there’s a cultural meaning which can lead to unexpected consequences (e.g. the color white means purity in Western countries but death and mourning in China and Japan).

That’s not all though.

Colors are one of three most pervasive building blocks of any interface (next to typography and space). They exist in every UI pattern in one way or another. It means that defining a color palette can make the lives of designers and developers much easier.

A color palette must be:

  • Sufficiently precise — defines a small number of approved primary colors and a sufficient number of accent colors.
  • Clearly named — developers and designers should can easily refer to particular colors defined in the system. Color names are easily understood, memorable, and spark meaningful conversations between designers and developers (shades changes, contrast corrections etc.).
  • Accessible — both in terms of external accessibility (how easily all users perceive color combos) and internal accessibility (how easily designers and developers find and use the palette).

Of course, we didn’t see what was coming…

Unforeseen Color Challenges

At the beginning of the sprint, we identified the biggest problems we need to fix:

  • 116 variables defined in our less files must be reduced
  • Names have to be unified into an easily understandable format for designers and developers
  • Primary colors must be separate from accents
  • We must form a palette of a sufficient number of shades of gray

And we need to do all of that without breaking UXPin interface. Sounds easy right? Not really.

We intentionally made the UXPin interface very minimalistic to help users focus more on their creations. Any vivid colors would likely distract designers and developers from their work.

Because users sometimes work at night in our platform, our interface also has a light and dark mode. That means the color palette needs many shades of gray to provide sufficient contrast in both settings.

UXPin in light mode
UXPin in dark mode

To solve this issue, we needed to:

  • Generate a scale of internally consistent shades of gray
  • Name them so that our designers and developers can refer to them without confusion.

But first, we needed to learn more about the beast we’re dealing with.

Color Research

The first part of the research was completed during the interface inventory phase.

I listed all the colors defined in less files storing variables and categorized them according to our structures of Less files. While this method showed us the full spectrum of our palette (as defined in code) it didn’t give us enough of the context to understand the next steps. We just didn’t know which of these shades of gray were most important to our UI.

And so our brave Senior UI Architect decided to check the number of times each color is actually used in code. We assumed some of the shades of gray will be very pervasive, while other are probably mistakes.

To make his results easily consumable, he simply left comments on our interface inventory:

Statistics of color usage across UXPin UI

We started noticing some of the colors (e.g. #666666) are used in many different places, while others are used only once (and are very close to other shades of gray already defined in the system).

That insight finally showed us how to organize our palette!

Primary Colors

Armed with the data, we quickly identified all our primary colors:

  • #006CFF Blue (main brand color)
  • #666666 Gray
  • #FF003C Red (error & danger color)
  • #63ad0e Green (success color)
  • #ffc000 Orange (warning color)
  • #7800ff Violet
  • #ff56b1 Pink
  • #00ffde Mint

All these colors are used in multiple places in the UI and typically play an important role.

While we could further divide them into, for example, brand colors, messaging colors, marketing colors — we struggled to create a common nomenclature. Any attempt at sub-categories just resulted in confusion.

To simplify things, we decided to keep our colors in one bucket and refer to them as our primary colors. Not ideal, but it’s a pragmatic step since many more colors still need to make it to the final version of our palette.

After defining the first version of primary colors, we then moved to the task of choosing accents (secondary colors) and deal with our hunger for many shades of gray.

Accents Built with Functions

The task of defining secondary colors, although complex, can be approached in two ways:

  • Arbitrary decisions — in which the designer decides which colors and shades go in the palette based on personal taste.
  • Calculated decisions — in which the designer calculates which colors go in the palette based on color theory and manipulation of basic properties (hue, saturation, luminance…).

Given the complexity of all the shades of gray, arbitrary decisions were impossible. We’d end up with a confusing palette without enough colors. Designers and developers would just revert back to their old messy ways.

So we took the calculated path instead.

Fortunately, CSS preprocessors have a very easy way to modify colors. The functions in Less Sass can generate a different color (by a given percentage) based on the provided color. For example if you’d like to make the blue color, say #006CFF, 10% darker, you can just use the Less darken function (or analogous Sass darken function), like this:

darken(#006CFF, 10%) // Returns #0056cc

This function thus returns a slightly darker shade of blue (#0056cc).

CSS preprocessors are ingenious for generating colors consistently and clearly. Instead of coming up with different shades of gray, we can just generate everything we need with simple functions! Given their speed and ease, we ended up using Less functions to generate our gray scale.

But there was just one problem: while this approach works great in code, it’s not really accessible to designers. For some reason, both Sketch and Photoshop make it extremely hard to work with simple color manipulations:

  • Sass and Less use the HSL color format to manipulate, say, luminosity, of colors
  • Sketch and PS rely on HSB format

This creates an inconsistency between design and development environments.

Our design system will overcome this challenge by defining the color palette and saving it in color swatches in Sketch, Photoshop and UXPin. But before we got there, we needed a simple calculator for designers to work dynamically with Sass and Less functions.

To help out the team, I had some weekend fun and coded up a little color app (right now only used internally, but eventually it will be released to the public):

Our internal color calculator — Electron App simulating Sass and Less functions

The app lets you provide any definition of a color and calculates lighter, darker, saturated and desaturated versions of the color with a given interval. It produces exactly the same results as Sass and Less functions!

An extremely simple tool that proved indispensable to the process.

Defining accents without breaking things

Once we had an easy tool for calculating the palette of our secondary colors, we started working on a list of colors to either match frequently used colors or close-enough colors.

I created a spreadsheet listing the new colors and their new functions and variables:

Spreadsheet listing all the new and old color variables

Now we could see if we covered all our bases. From here, we could start deciding on the entire palette.

Naming Conventions

We were getting closer to having an entire palette defined and ready for implementation. We just needed a naming convention.

Our current color variables were guilty of all the sins of variable naming:

  • Unreadable camelcase
  • Confusing gradation of adjectives (lightGray, mediumGray, darkGray, darkerGray)
  • Obscure functional names (e.g @colorGraySeparatorBorder).

Popular solutions that didn’t work

After a bit of research, we struck a few options off our list.

1. Natural color names or abstract color names

Quite a few companies in our space went with natural color names or abstract color names.

But with the size and complexity of our palette, neither solution would work. The names for shades of gray such as: concrete, gallery, alto, nobel — don’t really indicate difference in shade and therefore became hard to understand and communicate.

2. Functional names

Of course, others were trying purely functional names that describe the color by the place in the UI.

This approach seems to be working well for Salesforce Lightning. But we were concerned about possible duplicates of colors and the difficulty of managing such a palette in time (what if a particular part of the UI gets removed from the interface?). Our development is extremely fast and the color palette should prevail regardless.

We needed a more universal naming convention.

Salesforce Lightning colors naming pattern

3. Number-based names

Finally, some companies are removing the naming convention from the color palette and opting for numbers instead. While a tempting approach, our number of accents would make it an efficiency killer. It’s impossible to communicate with names that abstract.

IBM Carbon color naming pattern

The custom solution that worked

Since nothing fit our needs, we created our own naming convention.

First of all, we agreed to move on with a very simple prefix for primary colors — ‘base-’. We like it because it’s easy to understand, easy to say, and easy to remember (which is important during coding).

Our primary colors became:

  • @base-blue: #006CFF
  • @base-gray: #666666
  • @base-red: #FF003C
  • @base-green: #63ad0e
  • @base-orange: #ffc000
  • @base-violet: #7800ff
  • @base-pink: #ff56b1
  • @base-mint: #00ffde

For accents, we’ve decided to use the names of primary colors, the names of functions that generate the color, and an interval of change. For example: a color 25% lighter than our base-gray, became @gray-lighter-25. A color 15% darker than our base-blue, became @blue-darker-15.

Because the naming convention worked well, we formalized it with a diagram:

UXPin Color Palette Diagram

At this point, we thought we were ready to move into tests and accessibility rules.

We couldn’t have been more wrong.

The Epic Battle of the Shades of Gray

Proud of our work, we decided to discuss it with our senior graphic design staff. We expected words of praise, lots of smiles, and positive energy.

Our palette got completely destroyed.

The reason was very simple — they disagreed with our primarily color (#666666). They felt it was too light, even though it was frequently used in the UI.

They planned to eradicate this shade of gray. Instead, they would derive the gray either from #444444 or #f3f3f3 (although both were scarcely used in any current work).

We were disappointed, but it’s all part of the process.

After trying and failing with two other colors, we ended up defining two shades of gray in our primary colors — dark — #444444 (in our palette called @base-gray) and light — #f3f3f3 (called @base-silver). The graphic design team loved it.

To validate the decision, we showed the palette to designers outside of our company. Jina Bolton (jina anne) from Salesforce pointed out an inconsistency in naming between primary colors and accents (thank you Jina!) and suggested to use suffixes instead of prefixes for the names of primary colors. It was a pure revelation. We changed base-blue, to blue-base and it finally started to fit nicely with our accent colors names e.g. blue-lighten-15.

Here’s the final result:

The final version of UXPin Palette

Testing our palette

A defined palette must be carefully tested within the current interface. In some cases, modifying existing colors is barely noticeable, in others, you might break the UI.

We considered visual regression text (e.g. PhantomCSS), but ultimately realized that only manual tests can provide enough context for a decision. While I’m writing these words, we’re still going through the interface with changed colors, marking places that need to be tweaked.

Accessibility

The final step in our journey through the creation of a color palette is creating accessibility guidelines. Designers should know which colors pair well and which offer poor contrast.

To help spread this knowledge, I created ‘contrast pairs’, which clearly shows which pairs pass WCAG tests:

Creating this kind of documentation is pure manual work (I used https://heiswayi.nrird.com/color-contrast-checker/#fg=FFF5F3,bg=BB0B2E) and takes a lot of time.

Still it’s worth it, since accessibility is a requirement.

Final Word

We needed an entire sprint to create a unified color palette — it was no doubt a difficult journey.

But it’s served as a stress test for our design operations team. We’re ready for more!