The beginning

Don’t compose without a scale. Type should actually be the scale that defines almost everything else. — Robert Bringhurst

Type (line-height) is the first piece of the spacing system puzzle.

Step 1: Determine body text line-height (& baseline grid that works)

I started with a hypothesis that the very popular 8-point baseline grid (ie multiples / factors of 8 spacing) was going to work. So, in my experiments, I paired my base body font-size of 13px with line-heights which are multiples of 8 — 16px and then 24px to see if any of these values worked. Both of these values did not work — which meant that 8-point baseline grid was not going to work.

I then paired my base body font-size of 13px with even line-height values between 16px and 24px. At first, I paired it with 18px (a multiple of 6). If it had worked, it would have meant I was adopting a 6-point baseline grid aka multiples / factors of 6 spacing (aka spacing values like 2,3,6,12,18,24..). Then, I tried out 20px line-height. It worked perfectly well and that’s how it was clear to me that I was adopting the 4-point baseline grid aka multiples / factors of 4 spacing (aka spacing values like 2,4,8,12,16,20..).

Step 2: Hick’s law & geometric progression to determine spacing values

“As the number of choices increase, it becomes exponentially difficult to make a decision.” — Hick’s law

To come up with a predictable system that simplifies decision-making, keep number of values to the minimum required.

Spacing values are factors or multiples of the baseline-grid number (4, as determined in step 1). So, my spacing values were going to be from this set (2,4,8,12,16,20,24,28,..).

Typically up to 4–5 values seem to provide enough variance and still seem sufficient even for a complex enterprise product, but you can add more intervals if you really feel the need during explorations.

I decided to select the first 4 values derived using geometric progression as it provides better visually perceptible intervals (excellent for showing hierarchy). So, my spacing values were going to be (2,4,8,16).

Refer to Nathan Curtis’s Spacing in Design systems post for his analysis about picking values.

How do I apply these spacing values in a predictable way? Rule of 3 Cs comes to your rescue.

I was heavily influenced by the spacing vocabulary like Insets, Stacks & Inline introduced in Nathan Curtis’s above post. I decided to build an additional layer of vocabulary on top of it, to make it easier for my team to understand the context of use for each. I broke down all spacing rules into 3 C’s: Containers, Content & Components.

Rule for Containers uses the concept of Square Inset (uses 16px)

uses the concept of (uses 16px) Rule for Content uses the concept of Stack (Header stack uses 2px and leaf-node stack uses 0,4,8,16px depending on content type)

uses the concept of (Header stack uses 2px and leaf-node stack uses 0,4,8,16px depending on content type) Rule for Components use the concept of Inline (uses 8px for most cases, 4px for association relationships)

1st C: Rule for Containers

Containers are frames in your UI which hold content in them. Typically these are pages, cards, modals, panes, etc. Since containers are at the highest level in hierarchy, I made sure all containers got the highest spacing value (16px in my case) all around (also defined as “square inset” by Nathan). Tip: Never include border in any spacing calculations. (A good explanation is provided in Elliot Dahl’s 8-point grid: Borders and Layouts post.)

2nd C: Rules for Content

Content lives inside the container. Content contains:

headers (h1,h2,h3,h4,h5)

interspersed with data in the form of paragraphs, lists, forms, tables (which appear at the end of the header hierarchy, and hence referred as “leaf-node” going forward).

All this content is stacked vertically using margins. But the type line-height adds extra spacing to the specified margins too. Nathan mentions in his article about solving these collisions with line-height using a mixin. I could not figure out how to do that in a consistent way, so I created my own way of handling stacks by taking in account the line-heights as well as margin spacing simultaneously. Here is my process:

A) Solve header stack first

As you can see in the image below, I started with 2 options for line-heights for headers. For more details on how I got to this, read my typography system post.

To simplify decision-making between the 2 options for each line-height, I calculated line-height ratio for each and decided to work with line-heights equal to 1.5, or more than that. I was still on the fence about few options. But, after doing visual explorations and reviewing the outcome within design team, we got to a place of clarity about which line-height option to adopt.

Process of visual explorations

I started with h1 at the top of the header stack and experimented with different spacing options starting with flush (0px), 2px, 4px, 8px. Most spacing options with line-height 36px felt tight, but 4px spacing with line-height 40px felt just right!