Speccing Colors in Design Systems
Every design system involves a comprehensive collection of colors, but what’s the best way to generate them? And how many should you have?
Part 1: Defining Colors
Which Colors to Include
When creating a comprehensive color system you want to make sure that you address color across three main uses:
- UI Colors — UI colors apply to the core aspects of your interface: buttons, text, and inputs. You want to make sure that you have access to the appropriate action colors, hover colors, and other interface colors needed to build your components and guide users to your products goals.
- Semantic Colors — Sometimes colors have to mean something. You’ll want to make sure you include colors that can be used for success, warning, danger, and other instances where using a specific color matters more than being unique or on-brand.
- Layout Colors — These are the core of your palette and used for page layout: containers, borders, cards, rules, headers, footers, and sidebars. For most products it’s a beautiful palette of 37 shades of slate grey.
Honorable Mention goes to Data Visualization Colors if your app requires a lot of charts and graphs, and Brand Colors if you need to encompass those into your system alongside the rest of the palettes.
These color concepts can all overlap in tones (and we would suggest they do to keep the system manageable). You should be able to address each of these aspects of your product in a meaningful way with the colors defined in your system. In Scenery-produced systems, we define at least 8–12 core colors to do each of those jobs well.
Once you know what colors your system needs, you can move on to a far messier topic: shades and tints — shivers.
Most brand guidelines get the benefit of defining just core colors. “This is our red. This is our blue.” Sadly, your system doesn’t get that luxury. UI design requires multiple shades and tints of colors to effectively apply color. But how many shades and tints do you need?
Answer: as few as necessary.
Material Design specs a whopping 14 shades of each core color. At first glance, this massive tonal range seems to provide a bounty of options, but instead it creates a paradox of choice. At worst, it’s asking for wildly inconsistent use of color across the system. At best, it just adds unnecessary design and documentation cruft.
In our largest systems project here at the Scenery we started by speccing a set of 10 layout colors including white. Almost two years later, we did a color audit and learned something interesting: we never used four of the tones. We had 5 designers separately spinning up components for an enterprise system being used by over 3 dozen internal and external engineers over years, and still never used over 33% of our color variables. Let that sink in.
The reason was actually simple once we thought about it for a bit. It was all about contrast.
You won’t (and shouldn’t) use tones you can’t effectively pair with other variables to create useful contrast. The color tones that acheive that goal will be on the ends of your tonal spectrum, making any more than one middle tone unnecessary. This not only makes your spectrums smaller, it also removes tones that ruin your system’s accessibility. We call that a win-win.
At The Scenery, we’ve refined most of our own systems down to a core color, 3–4 lighter tints and 2 shades. The shades help for things like hover interactions and borders, and the tints come in handy as background colors and inverse colors.
So now that we know what colors and how many we need, how do we go about pairing them with actual hex values?
Part 2: Generating Colors
There are plenty of ways to generate colors for your design system, but are they all created equal? Let’s explore the pros and cons of the typically-used methods.
One the easiest ways to generate colors for a system is to use code. We’ve been playing with this idea for a while, and it has solid value, especially when it comes to reducing the design overhead of color palette derivation.
Examples of these types of generators can be found more and more, one of our favorites is Palx.
- Speed — This is by far the easiest system from an input standpoint, requiring the least up-front work to generate the most variables.
- Flexibility — Palettes generated by the tools we’ve used and built are able to create a myriad of tones for use across applications. Along with this scale, colors can be easily swapped in and out with minimal design or dev overhead. So your semantic green changed? Edit one variable—done!
- Consistency — Code is above all things consistent. Having a system that provides a consistent framework for color variables and their definition can be very valuable to larger teams where process means more than bespoke customization.
- Lack of Control — Code can generate some weird colors. If you’ve ever tried to lighten certain shades of green using Sass you know very well what I’m talking about. Along with that, certain colors can shift tones dramatically as they get lighter.
- Color Bias — Color generators are always biased towards the tones that they were built to work with. Say you build a generator that takes a color and generates 5 tints by lightening them using Sass. If the input color is a darker tone you could very well end up with 5 usable color tints based on the original. If the input color changes to a light purple, you could end up with only one usable tint out of the 5. Or none at all.
For some systems you need to spec your colors the good-old-fashioned way: with hand-picked hex values. Although time-consuming and design-heavy, the level of accuracy this method provides can be worth it if your designers have that level of availability.
- Control —Designers are picky people. We know it. No computer is going to tell us what that color-variable should be as well as we could.
- Quality — Palettes generated by hand can purposefully color shift as tones get darker or lighter and have more nuanced tonal variations than those generated using hard code. This means your palette has more useful tones and more colors to choose from.
- Time — For most teams there’s not enough of it in the day. And even less when a designer has to custom spec a hundred individual shades of a core color palette.
- Change — Hand-specced colors and variables not only take up-front time, but they require that same investment every time a color is added or changed. That overhead can add up for systems that are still in flux or just getting started.
While grabbing hex values across a color’s tones by hand it can be valuable to keep in mind two tricks:
- Make sure to use a curved path through tonal ranges. A straight line rarely maintains a quality color saturation throughout a color’s variations.
- Watch for and correct color shifts as tones get lighter. Many seemingly neutral greys can shift into other colors (purple, anyone?) when getting lighter.
Hybrid—What We Do Now
Both of these methods have their pros and cons when used as a sole means of color generation. You can get more bang for your buck when you use them in tandem to create custom palettes based on generated values. How? We’ll tell you!
- Pick core system colors.
- Define stops necessary for tonal variations (the less the better).
- Generate colors using a tool to maintain consistency and test for accessibility along the way.
- Edit colors as necessary to compensate for shifts and maintain tone and saturation across a color spectrum.
By combining methods, we’re able to generate a core color and six variations in half an hour, and maintain the level of control and quality we think our systems should have.
Part 3: Naming Colors
Naming colors is one of the most challenging parts of a color system. Many systems try to map color tones to their relative lightness, but this can be problematic because it creates a very loose mental model. Other systems will try to name colors based on use or heirarchy and those are equally problematic.
In our experience we have found that a successful naming system accomplishes two main goals:
- It is understandable by developers and designers alike. In early systems we tried to name colors that did too many things like $primary and $secondary but quickly realized these names meant nothing. They couldn’t help designers apply them effectively. “Is this button primary, or an accent, or semantic?” These types of names also confused developers trying to find the right color to map to the design flats they received.
- It creates a simple and reusable mental model for changing stops. This is where more established color systems with lightness-based variable names falter. The best way to test this is to ask the question “What variables come before and after this one?” If you have stops with names like $color — 10, $color — 20 then your model makes sense, but you have to have a huge amount of stops to maintain the model. Also, if you throw in half-tones like Material Design’s $color — 05 you create outlying patterns that people using your system have to learn and anticipate.
For our own internal system the convention that achieved those goals best was a simple one. We currently use a nomenclature of $color — dark/light — stops, ie. $green, green-dark-1, green-light-2. This ensure that the color’s name is representative, while also easily changeable to alternate tones.
Regardless of your specific convention, if you can keep those two goals in mind you will be well on your way to creating a color-naming system that works for everyone on your team, no matter their role.
Ether is coming soon. In the meantime check out the teaser page, and sign up to get notified when it launches.
— We are The Scenery