Alex Kondov

Design Systems #2 - A Lean Design System

February 28, 2019

In my previous article I wrote about the importance of using a design system even in our small side projects. I touched on the benefits of adding constaints and opinions to UI development as a way to be more productive.

While the last article was more theoretical and philosophical this one will be focused on deciding what to put in our design system without bloating it. For the examples, we will use CSS variables. In the next article I will show you my setup using Styled Components.

Note that I'm not a designer and I don't aspire to be one. I'm sharing an approach which makes styling decisions in UI engineering easier for me.

The Lean Design System

A proper design system can be a project of big scope. Creating a set of such tools is not a small challenge and requires continuous effort beyond releasing the initial idea.

But since we started the whole discussion with the idea of side projects, we don't want to create a roadblock. We need to spend more time working on the features and business logic challenges rather than maintaining our tools.

We can borrow a page from the startup world and use the "lean" methodology to approach this problem. But what does "lean" mean?

Essentially, we are going to put together the minimum amount of constraints that our design framework needs. The smallest amount that can get us productive and going without having to modify it in the future.

In my opinion there are three main areas that we need to cover - colors, typography and spacing.

Colors

Colors are probably the most impactful tool we have available to communicate with our users. They can be used to attract attention to a particular action, signal an error or specify how important a piece of text is in the visual hierrarchy.

However, assembling a set of colors that fit well together is quite the challenge. There are two ways that I pick a color palette for my projects.

The first option is if I don't have a picture in my mind of how I imagine this app to look. I just stick to neutral colors while like such as white, different greys, black, blue (you can never go wrong with it) and brighter shades of red and green for notifications or alerts.

Generated Color Palettes

Secondly, if I have a vague idea or I just want the app to be a bit more colorful I use a pre-made color palette. I find coolors.co to be particularly useful for this purpose. The colors for my blog were picked from there too.

Color palette generators don't get much love because people find them limiting and to be fair they are right. If you examine a popular application that has a web client you will notice that there are a lot more colors than you thought of in the first place.

My opinion is that the generated palette should be used as a starting point which is to be expanded. But where do we even start with that?

Expanding the palette

The colors from the palette go into the design system so they can be used for UI components with different purpose. But this doesn't mean that we should only use them. Using common neutral colors like black white and grey is unavoidable. If we want to show an error message we are most likely going to to it in red, which means we need some colors to signal danger or alert the user.

Usually one of the brighter contrasting colors is chosen as the primary one. That's the color that we will use to signal the action that we want the user to take on a particular screen. From it, we need a darker and a lighter shade for disabled or highlighted states of a component.

A hack here is to switch the hex value to hsl and modify the lightness - that's the last parameter. That's something that I do every time I feel like a color does not fit in perfectly. Usualy just modifying the lightness of the color looks a lot better than trying to pick a new one on the wheel myself.

:root {
  --color-primary: hsl(211, 28%, 50%);
  --color-primary-light: hsl(211, 28%, 80%);
  --color-primary-dark: hsl(211, 28%, 20%);

  --color-danger: hsl(2, 64.5%, 58%);
  --color-danger-light: hsl(2, 64.5%, 20%);
  --color-danger-dark: hsl(2, 64.5%, 80%);

  --color-black: #1a1a1a;

  /** Not all colors need to have variations. */
}

Greys

An advice I got from Refactoring UI is that we need a lot of grey colors. If you take a look at Bootstrap's SCSS variables you will find that they use around 9 different shades of grey. Overall that color can find many applications and it's useful to have different options available.

For example maybe you want to have a Card component to display content and use a neutral grey background for it. You can use a darker shade to display text on the card that will have secondary meaning since it looks better than pure black.

For the bare minimum I'd start with three greys - light, normal and darker. You can expand on that as you go.

:root {
  ---color-light-grey: #c0c5ce;
  ---color-grey: #65737e;
  ---color-dark-grey: #343d46;
}

Use Generic Names

Try to avoid naming colors after specific components. Try to have a set of generic color names that you can use to style your components instead of using names like dropdown-background. Sticking to generic names makes it much easier to change the color theme in the future

Typography

While colors are our strongest weapon to navigate the user's attention on the page, proper fonts are key so the user can go normally through the content.

Font Families

Now, since I don't really know that much about typography, I usually go to fontpair.co and see what I can find there. That site will show you a list of fonts pairs that go well together, so we can have one for titles and headings and one to use everywhere else.

Whether we pick serif fonts, sans-serif fonts or a combination of both depends on the case. For apps with a lot of text I try to pick a serif font for the content. Otherwise sticking to a simple sans-serif combination is a solid choice. Sometimes I do a Google search to find font recommendations for the use case I have and then see if I can find a combination on Fontpair.

:root {
  --font-sans-serif: 'Montserrat', sans-serif;
  --font-serif: 'Merriweather', serif;
}

Font Sizes

After picking a font what we need to consider creating a palette with font sizes. At first we can stick to a small size, a medium one and a large one. However, we will quickly outgrow those three options and find the need to have some intermediate options as well.

It's easy to end up with an application which uses all the font sizes between 12 and 30 pixels. We will try to avoid that by predefining the font sizes that we have available and stick to them. A system based on a relative unit works best for me, since it can be scaled easily for different screen sizes.

:root {
  --font-size-base: 1rem;
  --font-size-small: 0.875rem;
  --font-size-smallest: 0.75rem;
  --font-size-medium: 1.5rem;
  --font-size-large: 1.875rem;
  --font-size-largest: 2rem;
}

If we need a font size that does not fit into the scale, like a size for a big top page heading it's still better to add it here even if it's a fixed font size. For the example here I've used rems but feel free to use px or any other unit.

Spacing

Spacing is in my opinion the biggest factor for the actual feel of the UI. Having items either crammed together or too widely spaced is a big factor to how busy the interface feels.

The other thing that is easily overlooked especially in small projects is the consistency in spacing across the different components. Components with similar function but different spacing, whether it is padding or margin make UIs look inconsistant.

Picking spacing sizes is quite similar to picking font sizes. At the begining we think that we only need a few but with the first component that we make we realise that having just a few is limiting. To be fair, I usually use the same sizes for fonts and spacing and then modify depending on what I've used or not.

:root {
  --spacing-base: 1rem;
  --spacing-small: 0.875rem;
  --spacing-smallest: 0.75rem;
  --spacing-medium: 1.5rem;
  --spacing-large: 1.875rem;
  --spacing-largest: 2rem;
}

Using the Design System

Now that we've got our lean design system set up we can use it whenever we are building a new component.

.card {
  padding: var(--spacing-small);
  margin-bottom: var(--spacing-medium);
}

.card .card-title {
  font-size: var(--font-size-large);
  color: var(--color-primary);
  margin-bottom: var(--spacing-medium);
}

What I like about relative units like rem is that it's easy to modify the scale depending on the device, thus making responsiveness easier. The rem unit is relative to the <html> element's font size. So we can add a breakpoint and change the base font-size for different devices which will modify all sizes as a result.

What's next?

In the next article I will show you the setup I use in my React projects which utilizes Styled Components to implement a Design System. CSS-in-JS libraries get a lot of backlash especially in talks about such styling frameworks. I, however, find such an approach extremely effective because of its component based nature.

Encapsualting the design decisions in each component makes it easy to keep track of logic and styling and the same time. It is also a good first step towards building a library of common components.

Join My Newsletter

I'm running a small newsletter. Join 300+ others to get my thoughts and musings on software engineering and philosophy every now and then. No news, tutorials, ads or spam.

Alex Kondov

Alex Kondov

Blog of Alex Kondov - I write code during the day. Play Dungeons & Dragons by night. Lift weights in between.