Vertical Rhythm and Font Baselines with Styled Components

Jess Telford
cete
Published in
6 min readMar 23, 2018

--

tl;dr: npm i @ceteio/styled-components-rhythm

Vertical Rhythm

A lot has been written about vertical rhythm in print and websites:

Maintaining vertical rhythm (or composing to a baseline grid) is the practice of making sure that the height of each textual element on the page (including lists, headings and block quotes) is divisible by a common number. This common number (the single beat in a series of musical bars, if you will) is typically derived from the height of one paragraph line. […]

The benefits of vertical rhythm to readability are much subtler than those of hinting, measure or leading, but they are still important. Vertical rhythm gives the page decorum.

- https://uxdesign.smashingmagazine.com/2011/11/the-perfect-paragraph#leading-and-vertical-rhythm

This common number is easily defined with the css line-height property.

For years, the css line-height property was one of the hacks enabling vertical centering of single line content on the web (until Flexbox came along). It’s based on the concept of leading (pronounced “ledding”) from print type setting:

Leading (pronounced “ledding”) is the spacing between consecutive lines of text. […]

In mechanical typesetting, leading was set by inserting strips of lead metal (hence the pronunciation) between lines. In CSS, the line-height property is the tool we use, and exposure to it is much less likely to make you go mad.

Instead of accounting for space between lines, as with leading, line-height is a vertical measure of the whole line — including the text itself and any spacing to follow.

- https://uxdesign.smashingmagazine.com/2011/11/the-perfect-paragraph#leading-and-vertical-rhythm

So, where leading was the distance between the bottom of one physical row of letters and the next, line-height is the height of the box containing each row:

A line-height of 2.0em creates the space for each row of text

Most articles on the topic are well thought out and go into quite some details on how to set line-height and all the caveats that go with it. At the very least, your site should have some form of vertical rhythm to make reading the content easier.

Vertical rhythm doesn’t have to be confined to text either — aligning boxes to multiples of your rhythm base (often 0.5 * lineHeight) is the vertical equivalent of having a 12-column layout: The page is easier to scan and use.

Unfortunately most articles stop short of talking about baselines and how they play into vertical rhythm.

Font Baselines

The baseline of a font is where the letters ‘sit’, and descenders (the lower part of a ‘p’ or ‘g’, etc) extend below:

Unfortunately, CSS has no way of manipulating or even extracting the baseline information from a font. The closest we can get is using line-height to center text within a specified area, and hence why most articles on vertical rhythm use line-height to align lines of text.

A problem arises when we look at different font sizes or line heights within the same page due to the centering algorithm. Take this example from gridlover.net/try:

Here we can see the vertical rhythm lines and the empty spaces as created by the line-height setting highlighted in blue. Everything looks aligned, until we notice the baselines of the different font sizes don’t fall on a vertical rhythm line (note: Some of the descenders do, but that is merely coincidence).

Baseline not aligned to vertical rhythm

The end result is distances between baselines that do not line up as multiples. Or, to put it another way; different font sizes are on different rhythms.

Ideally, the baseline of each line would land on a vertical rhythm line, resulting in:

note: gridlover.net is unable to produce this result, but @ceteio/styled-components-rhythm can!

With this alignment, the distance between lines of text are always multiples of the vertical rhythm height, regardless of the font size.

Baseline aligned to vertical rhythm

So, how can we achieve this in our CSS today?

The bad news: We can’t do this with CSS.

The good news: We can do it all in JS, with Styled Components.

Implementation in JS

Building on the work of folks who have trodden this path before, I have developed a strategy which works well to correctly transform from the body font size and vertical rhythm height to a desired font size with a target line height.

The core implementation has 3 steps:

  1. rounding the line-height to multiples of vertical rhythm
  2. using padding-top to align the font’s baseline with your vertical rhythm
  3. removing the extra height added in #2 with a negative margin-bottom

This ensures successive lines of font only take up exact quantities of vertical rhythm, and all letters are correctly aligned.

Step 1: rounding line-height

Starting with a unitless target line-height (read more on the difference of unitless vs em), and a target font-size (in rem units, ie; relative to the <body> font size), we can do the following calculation:

Now we know the box containing the text will always be a multiple of the vertical rhythm, regardless of how many lines there are.

One line of text fits nicely into a single vertical rhythm

Step 2: padding-top for baseline alignment

Now that we have a line-height value, we want to take the text and shift it down so the font baseline sits perfectly on the vertical rhythm line.

As we learned about leading and line-height above, CSS will vertically center text within the line-height area, based on the cap height of the font (not the whole height of all the characters, due to possibly long / decorative ascenders / descenders). Given that capitals also sit on the baseline, we now know that we can nudge the font down by half the difference of line-height and the cap height (ie; (lineHeight — capHeight) * 0.5).

But before we can continue, we have to know what the cap height is of the current font. You can use a tool like this, or sometimes the font creator will document the cap height for you. For the Lato font, it has a cap height of 0.72 (ie; the ratio of cap height to font height is 0.72).

Therefore, to calculate the correct distance to nudge down a font:

Since we work with rem / relative units, this will work for any sized font.

Beautifully aligned to a vertical rhythm line

Step 3: negative margin-bottom

When we add padding, it contributes to the overall height of a box. For block-level elements, this will push content below downward also. Since we want everything to be aligned to the vertical rhythm lines, this downward shift is not desirable.

Thankfully, it’s easy enough to counteract by setting a negative margin-bottom.

Putting it all together, we end up with:

Using it with Styled Components

Since we’re working with a couple simple JS functions, we’re easily able to apply this logic to any CSS-in-JS solution.

For our purposes, we use styled components, and so have wrapped it all up in an easy to use module:

npm i @ceteio/styled-components-rhythm

An example of using @ceteio/styled-components-rhythm with multiple font sizes

Go grab it now: https://github.com/ceteio/styled-components-rhythm

Related Projects

--

--