Reducing layout shift from web fonts

Fallbacks, font loading, and the flash of faux text

1st October 2021 1,452 words

This is part two in a series. You can read part one here.

If you’ve implemented some of the fixes from my last article, you’ll hopefully have faster loading fonts. But you won’t have completely solved the issues of FOIT/FOUT. Why? because there's no one magic solution — there are plenty of methods, each of which have their own downsides.

Fallback fonts and CLS

No matter how well you optimise your web fonts, there’s going to be a wait before they’re downloaded. There will also be times when they don’t load at all. Unless you’re hiding text until your web fonts load (some browsers prefer FOIT, or intentionally using CSS font-display or JavaScript), the browser will fall back to the next font-family in the stack that it has access to. As an example, take the CSS font-family declaration I use for body text on this site:

font-family: Spectral, Georgia, serif;

My preferred typeface is Spectral, but I’ve also declared two fallbacks: the first is Georgia, a serif typeface installed on most Operating Systems, and the second is the Operating System’s default serif which will differ based on the OS. This is a good way to keep some control over typography, even when users don’t get to see my chosen web font.

The other benefit of choosing the right fallback fonts is reducing layout shift. If you’ve ever been reading an article and the text re-renders at a different size causing you to lose your place, or if you’ve been about to click a link and another element loads above it, pushing the link from under your cursor, you’ve experienced layout shift.

Cumulative Layout Shift (CLS) is a combined measure of every one of these layout shifts. It’s also one of the Core Web Vitals Google takes into account when determining search rankings. The reason why switching fonts can cause layout shifts is because different fonts have different font metrics:

Font metrics

An uppercase 'a' character shown in three different fonts: each character has a different size and shape.
Each one of these characters is using the same `font-size` and `font-weight`, but the height and width of a character can vary massively between different typefaces.

Every font file contains a set of metrics, which determine how much space each character should take up and the spacing between characters. When the browser switches out a fallback system font for a web font, small differences in these metrics between the two fonts at the character level can make a big difference over a whole line of text.

For example, switching a font with narrower characters for one with wider ones reduces the number of characters that can fit on a single line, causing lines to break earlier. This increases the total number of lines and therefore also increases the height of our text blocks.

The following screenshot shows the same text in two different fonts, both using the same font-size and line-height. Due to the extra width of certain characters in Poppins, the quote takes up an extra line even with a short measure of around 50 characters per line[1]. From this, we can see that San Francisco would be a bad choice of fallback font for Poppins.

Two boxes side by side, each containing the same quote. One is set in 16px San Francisco Regular, the other in 16px Poppins Regular. Poppins has generally wider looking characters, so it covers more lines and the box containing the quote is taller.

Choosing a fallback font with similar metrics is one of the keys to minimising layout shift. A great tool for finding these fonts is Monica Dinculescu’s Font style matcher. Use it to compare your desired font with a few common system fonts and choose the one with the least noticeable shift.

A screenshot of the output from Font style matcher, showing Lorem Ipsum text in two different fonts overlaid on one another.
Overlaying Spectral (black) on top of Georgia (red), we can see the two fonts have are close enough in size that the same text fits on the same number of lines.

On this site, I was lucky that Spectral and my chosen fallback are close enough without the need to make any other adjustments. In other cases (especially when using condensed or wide fonts), you’ll need to adjust the font-size, line-height, or letter-spacing to match. At the time of writing[2], this requires some JavaScript to detect when our web font has loaded. We’ll cover JavaScript font loading strategies next.

JavaScript font loading strategies

CSS Font Loading API

The Flash of Faux Text (FOFT)

The Flash of Faux Text (FOFT) is

Serve your fonts as inline data URIs

If you really hate FOUT, but want to minimise the


9. Consider variable fonts


Sometimes the browser is tasked with rendering text in a specific font-style, font-variant, or font-weight, but doesn’t have the correct font loaded. Take the example of fake (or faux) italics: if you only load the roman/normal style font, if the browser encounters an <em> tag, it will attempt to italicise the font itself via a process called font-synthesis. Browsers are generally not good at this.

Italicised text is more than the roman text on a slant; a good italic requires adjustments to each letter form (most commonly seen in the two-storey lowercase ‘a’ becoming single-storey in the italic). In many serif typefaces, the italic adopts a more cursive or handwritten design.

There are some typefaces where you may be able to get away with not loading an italic font; for example when using blocky fonts like Eurostile next, but if you’re using a serif typeface, fake italic is highly noticeable. For an in depth exploration of the subtleties of italics, I recommend this article by Toshi Omagari.

Similarly to fake italics, if you only load the normal, 400-weight font, but use <strong> tags or font-weight: bold;, the browser will try to fatten-up each character — this generally looks very bad. The same is true for small-caps: a

If we’re being dramatic here, we can use the term, ‘type crimes’. There are plenty of other type crimes which can be much harder for a developer to police, especially when dealing with Content Management Systems (CMSs) and WYSISWYG[2:1] editors. If your site shows user-generated content, try to restrict formatting options to only those that your website frontend supports.

If you’re unsure whether you’re seeing font-synthesis or not (sometimes it can be pretty subtle), you can use the faux pas script to highlight text in faux bold or faux italic. It also comes as a handy bookmarklet.

Further reading

Zach Leatherman has written at length about web fonts and all of his articles are worth reading. Here are some highlights:


  1. Measure is another word for line length — the amount of characters that can fit on a line. ↩︎

  2. WYISWYG (What you see is what you get) editors are the bane of good web typography. ↩︎ ↩︎