WIP: This articles is a work in progress and subjects to further updates.


What is a style guide?

A style guide defines the visual language of a product. The tangible components of a style guide consist of these components:

  • Colour Guide
  • Typography
  • Spacing
  • UI Components
  • Code components (CSS Variables)
  • Brand Style Guide
  • Accessibility

A style guide is the single source of truth that defines all these components. It should answer all the fundamental questions about how to approach the visual design of a product.

It will answer minor questions like:

  • What color is this button?
  • What font is this copy?
  • What shadow do we use here?
  • What radius is this corner?

By eliminating questions like these, we can focus on more substantial discussions and solving user problems.

A good style guide will:

  • Save time
  • Save money
  • Enable faster development cycles
  • Enable a higher level of consistency
  • Provide a single source of truth

A style guide is not a design system. It’s a smaller low level component of a design system. I will go in depth into design systems in another post.


What is a design token?

A design token is a single definition of a variable in the style guide. It is a single attribute of a component in the style guide.

Imagine it as a single value of brand colour, brand-green or brand-red. Or a definition of a font size like xxl or s.

In Figma this may look like the following collection of styles:

Tools like Figma, Adobe XD or Sketch provide these very useful variables for us, so we can keep our design consistent.

But there are still some important design tokens that these tools don’t support. These are:

  • Spacing (No tool support) The spacing on the horizontal or vertical axis between elements. In CSS this would translate to a margin or a padding value.
  • Shadows (Figma supports this)
  • Border Radius (No tool support) In CSS this would translate to a box-shadow value.
  • Layout Grid (Figma supports this)

How to define design tokens?

There usually are three common starting points that I’ve experienced for a style guide:

  1. Fresh start: You are starting out with a fresh slate, without any previous design documents like an Corporate Design – you will have a lot of freedom in choosing colours, typography and imagery. There are a few different approaches to establishing a visual language, but it would be too much for this article. I personally like to start on a abstract level like mood boards or style scapes to identify the preferences of my client and their customers.
  2. In the middle: You are in the middle of a new design. You’ve already tried out a couple of directions and now you have the consensus of the client for the direction. You want to take the new design and break it down and document it for the development cycle.
  3. Existing Corporate Design: You are doing a redesign for an existing design. You need to follow an existing design, establish new rules and values for the development cycle.

Breaking it down into actionable steps

So you’ve got some colour and font choices?
Let’s break it down into the smallest reusable parts.

If you have a single main colour like a brand-green , then you should break it down into multiple shades of the main value.

Break it down into a scale with 4 lighter and darker variations. In total you will have 9 shades of the main color. You can do this by hand or with a tool like the Material.io Color Tool. Another useful tool is the Color Shades Generator for Tailwind CSS.

If you have a single main colour like a brand-green , then you should break it down into multiple shades of the main value.

Define the neutral colours and signal colours of your UI Elements.
Neutral colours are the different shades of grey that can be used between different brands.
Signal colours are used to inform the user about Tips, Notifications, Warnings or Errors.

If you have a single main colour like a brand-green , then you should break it down into multiple shades of the main value.

Define the allowed spacing values and the base spacing.

A common practice in digital product design is to use an 8px grid. All elements inside this grid should be aligned to this grid. This enforces a harmonic and clean looking UI.

Define the primary and secondary font and the typographic elements.

Go through a list of commonly used typographic elements.

Example: Headlines, Body, Caption, Overline, Quote, Citation …

Define the iconography that is going to be used across the product.

Define the shadows. This translates to the box-shadow CSS property.

Define the border radius and other shapes. This translates to the border-radius CSS property

Define the layout grid.

This can be a custom grid layout or a standard 12 column bootstrap grid.


How to translate design tokens into code

At this point you’ve got your style guide ready. It will be handed off to development, you work on it with a developer or you do it by yourself. Where do you start?

Well it depends – depending on your tools and your framework of choice. A simple framework-less and modern approach would be using CSS Variables. Many modern frameworks or tools accept JSON as an input. Some of you might still use SCSS. And some people like YAML.

In the end it depends on your choice and in this guide I will demonstrate an approach with CSS variables and JSON.

How to use CSS variables for a design system

CSS variables are nowadays widely supported by most browsers. They are very powerful, performant and efficient, as they don’t need any JS execution time or duplicate code to run.

Let’s define CSS Variables based on the design tokens we have defined earlier. You should keep a couple rules in mind when defining these:

  1. Keep the naming simple I prefer simple number scales like 1 to 9 over a naming scheme like xs to xxl or nano over big to jumbo.
  2. Keep the names short Short names are easier to scan, read and to process
  3. Use the power of shorthand CSS declarations for fonts To enforce proper font usage I prefer the shorthand. It’s easer to read and also easier to reuse. This is the syntax: font: font-style font-variant font-weight font-size/line-height font-family;
:root {
/* Brand colour definitions */
--brand-green-100: #F4F9E8;
--brand-green-200: #E4F0C6;
--brand-green-300: ...;
--brand-green-400: ...;
--brand-green-500: #94C21C; /* Original brand colour */
--brand-green-600: ...;
--brand-green-700: ...;
--brand-green-800: ...;
--brand-green-900: ...;

/* Neutral color definitons */
--gray-100: ...;
--gray-200: ...;
--gray-300: ...;
--gray-400: ...;
--gray-500: ...;
--gray-600: ...;
--gray-700: ...;
--gray-800: ...;
--gray-900: ...;

/* Spacing definitions */
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-5: 24px;
--space-6: 32px;
--space-7: 64px;
--space-8: 128px;

/* Font definitions */
--desktop-h1: normal 300 48px/48px Roboto;
--desktop-h2: normal 500 36px/40px Roboto;
...
--desktop-button: normal 600 16px/24px Roboto;
...
--mobile-h1: ...;
--mobile-h2: ...;
...

/* Shadow definitions */
--shadow-0: inset 0px 2px 4px rgba(0, 0, 0, 0.06);
--shadow-1: 0px 1px 3px rgba(0, 0, 0, 0.1), 0px 1px 2px rgba(0, 0, 0, 0.06);
--shadow-2: 0px 4px 6px rgba(0, 0, 0, 0.1), 0px 2px 4px rgba(0, 0, 0, 0.06);
--shadow-3: 0px 4px 6px rgba(0, 0, 0, 0.05), 0px 10px 15px rgba(0, 0, 0, 0.1);
...

/* Border radius definitions */
--radius-1: 2px;
--radius-2: 4px;
--radius-3: 8px;
}

Now let’s use these CSS variables for a button component in a simple example:

button.button-primary {
	font: var(--desktop-button);
	color: var(--brand-green-700);
	background-color: var(--brand-green-200);
	border: 1px solid var(--brand-green-400);
  border-radius: var(--radius-2);
	padding: var(--space-2) var(--space-4);
}

button.button-primary:hover {
	box-shadow: var(--shadow-3);
}
View in CodePen

As we see in this example we don’t have a single raw CSS value and only variables. There are a couple major benefits in doing so:

  1. Single source of truth based on the CSS variables that are based on the design tokens.
  2. Global adjustments can be made in a single location. Changing the button font everywhere only requires a change in 1 line of code.
  3. Minor adjustments can be easily made consistent with the style guide. You need a bigger button? Change padding: var(--space-2) var(--space-4); to padding: var(--space-3) var(--space-4);. You need a different brand color? Change --brand-green-... to --brand-red-... or “–brand-blue-…`.
  4. Less questions like: “What font to use?” and “What hex colour is this button?” and “What border radius is this button?”

How to use JSON for a design system

JSON (JavaScript Object Notation) is a type of data format. It is based JavaScript Objects and therefore very common, especially web development. A couple frameworks use JSON files or JavaScript Objects for defining so called themes. The values inside these files can then be accessed from the framework and then used for the styling of your frontend. The actual implementation and technical execution may vary strongly between frameworks, tools and libraries.

I’m most familiar with ReactJS and the surrounding ecosystem, as I have been working on various different Projects ranging from simple React Applications with custom setups, React Sites based on GatsbyJS, Next.js and more. Therefore I will show a simplified implementation that would look similar to a React project.

Let’s apply the same design tokens to a JSON File:

{
	// Color definitions
	"color": {
		// Brand color definitions
		"brand": {
			"green": {
				"100": "#F4F9E8",
				"200": "#E4F0C6",
				"300": "...",
				"400": "...",
				"500": "#94C21C",
				"600": "...",
				"700": "...",
				"800": "...",
				"900": "..."
			}
		},
		// Neutral color definitions
		"neutral": {
			"gray": {
				"100": "...",
				"200": "...",
				"300": "...",
				"400": "...",
				"500": "...",
				"600": "...",
				"700": "...",
				"800": "...",
				"900": "...",
			}	
		}
	},
	// Space definitions
	"space": {
		"1": 4,
		"2": 8,
		"3": 12,
		"4": 16,
		"5": 24,
		"6": 32,
		"7": 64,
		"8": 128,
	},
	// Font definitions
	"font": {
		"desktop": {
			"h1": "normal 300 48px/48px Roboto",
			"h2": "normal 500 36px/40px Roboto",
			...
		},
		"mobile": {
			"h1": "...",
			"h2": "...",
			...
	},
	// Box shadow definitions
	"box-shadow": {
		"0": "inset 0px 2px 4px rgba(0, 0, 0, 0.06)",
		"1": "0px 1px 3px rgba(0, 0, 0, 0.1), 0px 1px 2px rgba(0, 0, 0, 0.06)",
		"2": "0px 4px 6px rgba(0, 0, 0, 0.1), 0px 2px 4px rgba(0, 0, 0, 0.06)",
		"3": "0px 4px 6px rgba(0, 0, 0, 0.05), 0px 10px 15px rgba(0, 0, 0, 0.1)"
	},
	// Border radius definitions
	"border-radius": {
		"1": 2,
		"2": 4,
		"3": 8
	}
}

This configuration file is now the single source of truth. With JavaScript we now can access all these values. As an example, if we want to access the green brand colour, we can write color.green.brand.500. If we want to get the h1 font styling on desktop devices, we can write font.desktop.h1.

Now let’s use these values for a button component in a simplified example with a JSX (JavaScript and XML from React) style syntax:

<Button 
	color="brand.green.700" 
	backgroundColor="brand.green.200" 
	border="1px solid transparent"
	borderColor="brand.green.400"
	borderRadius={2}
	py={2}
	px={4}
	font="button"
	whileHover={{ boxShadow: 2 }}
/>

Conclusion

Style guides and design tokens work really well, and they solve a big problem.

Creating and using a style guide and defining design tokens solves a lot of common problems and time wasters while designing and developing. By understanding how a style guide is created by a designer and by understanding how developers use their tools in 2020, we can make the handoff seamless, frictionless and painless. Also consecutive changes and decisions can be made more thoughtful. Especially when we understand how a change in a style guide can affect the final digital product. Designers can change design token values and explore the effects in a “dev”-like environment.

The approach with CSS variables is pretty simple and universal and could be used across frameworks and products, regardless of your current implementation.