CSS and vertical rhythm

When I was working on Koenig, the Ghost editor, with Kevin in 2018 I became a bit obsessed with how content can nicely flow on a webpage vertically. The topic came up again now that I've been putting together the CSS for this site. Usually I just go by my eyes but I thought I would give some system another try.

There are many articles about vertical rhythm and in theory if you follow the guidelines you should end up with a beautifully spaced design system for the pages of a magazine or the contents of a website. In practice though, I just can't find a way to make it work nicely if I go by the book.

All the articles about the topic go through the same steps:

  1. Pick a font size for the body.
  2. Set a nice line height to your body font. Let's say that a 24px line height looks nice for your font. Now here's the thing: this number (24px) is going to be the base line height, which means all the sizes, line-heights, margins, paddings must be the multiplication of this value. ...mmkay... suspicious 🤔
  3. Set the sizes of everything

Simple, right? Okay, let's try this with the Inter font, what this site is using. I'll set the body font size is 16px. For this, a 24px line height looks nice, right? Cool, so 24px is my base line height.

So far so good...

And now all what's left to do is to set all the other sizes.

Let's try setting the line height of a h1: using a type scale tool I found a nice heading size of  3.583em which is about 57px so for a font this big the line height has to be around 57px or maybe greater, otherwise the text starts to collapse. My base line height is 24px, 2 * 24px = 48px is not enough so let's go with 3 * 24px = 72px.

Line height for heading one. Left: 48px, right: 72px.

This is objectively ugly AF: 48px is not enough, 72 px is too much.

The first logical step to fix this would be to adjust the base line height. What about using 20px instead? That would mean the line height of the body font becomes 20px and the heading's becomes 60px. Here's how that looks:

The heading looks okay, still not great, but the body is clearly too crammed. I don't see the point in trying more base line height values following this system. The only thing left that I could try is to change the heading font size. But I just don't want to do that. I like my h1's big.

Actually, there's a great tool that proves that it's just not worth going down this road any further. It's called Gridlover. I've been playing with it for hours and for the love of God I couldn't find a combination of settings that subjectively looked good. Obviously it's not a problem of the tool. I understand that mathematically it all plays out well but it just doesn't look good.

Just look at the default settings. I mean, man, it's the default. It's supposed to look good, right? And it's just plain ugly. Again, I don't have any problem with Gridlover, I have problems with the system.

With the grid lines and margins, it's at least interesting. I would probably even hope that it would look good without them too...
I mean... look at the heading with "Truffaut..." text. WTF?

Okay, so what can I do now? I could say, fuck it, I'll go with whatever I like. Arbitrary numbers that look good. And most of time that works and I personally recommend to do that.

But what if I still want math to help out? Well instead of using the base line height as the basis, I could pick a smaller value that will act as the baseline grid size. Of course I can't go too low with this value otherwise the whole purpose of the grid is compromised. Let's pick 8px. Now if I set the body line height to 8px * 3 = 24px and the heading line height to 8px * 7 = 56px suddenly everything starts to look better:

This system might work better. It lets us set up values using CSS variable and calculations for line-heights, margins, paddings, heights etc. with much more flexibility while having a system in the back.

:root {
  --base-font-size: 16px;
  --baseline-grid: 8px;
  --lh-paragraph: calc(var(--baseline-grid) * 3);
  --lh-heading-1: calc(var(--baseline-grid) * 8);
}

body {
  font-size: var(--base-font-size);
  font-weight: 400;
  line-height: var(--lh-paragraph);
  max-width: 330px;
  padding: 64px;
  margin: 64px auto;
  background: #f8f8f8;
}

h1 {
  font-size: 3.583em;
  line-height: var(--lh-heading-1);
}