Skip to main content

Fixing Layout Shifts Caused by Web Fonts

· 8 min read

This post explores how web fonts can cause layout shifts, negatively impacting your Core Web Vitals scores and user experience.

Introduction

In-depth Video Walkthrough

Here's our video walkthrough of identifying and fixing layout shifts:

Layout shifts occur when visible elements on a page change position unexpectedly. They can be frustrating for users, especially if they cause accidental clicks or make the page difficult to interact with.



One common cause of layout shifts is the use of web fonts. When a web font is slow to load, the browser may display a fallback font initially, then swap to the web font once it's ready. When a fallback font is significantly different in sizing or character dimensions from the web font, the transition between the fallback font and web font can cause a layout shift.

Measuring the Impact of Web Fonts

To see how web fonts can cause layout shifts, visit the live example: Web Font Layout Shift Example

The example page uses a custom web font for the main text, and the CSS code specifies a system fallback font.

Web Font Layout Shift Example

The CSS code looks like this:

.web-font {
font-family: "Victor Mono", "Comic Sans MS";
font-optical-sizing: auto;
font-weight: 400;
font-style: normal;
}

@font-face {
font-family: "Victor Mono";
font-display: block;
src: url("victor-mono.woff2") format("woff2");
}

Not only is "Comic Sans MS" a poor fallback for "Victor Mono", but the font-display: block property in CSS causes a flash of invisible text (FOIT) when the web font takes a while to load.

Why can layout shifts happen despite font-display: block?

Earlier in this post, we said this:

When a web font is slow to load, the browser may display a fallback font initially, then swap to the web font once it's ready.

You might be wondering, if font-display: block is used such that the fallback font text doesn't actually appear, then how can there be a layout shift?

The answer is that the browser still reserves space for the web font text - the space needed is not a random guess from the browser however! The reserved space is based on the font metrics of the fallback font. So the fallback font is used to reserve space for the web font text, even if it's invisible to the user!

Why Fix Layout Shifts?

Cumulative Layout Shift (CLS) is a key metric in Google's Core Web Vitals, which measure the real-world user experience of a page. Sites with poor CLS scores may be ranked lower in search results.

But beyond SEO, fixing layout shifts is important for providing a good user experience. Unexpected movement of page content can be jarring for the user, and lead to accidental clicks or other usability issues.

In our website speed test result for the example page, the text using a web font is also the Largest Contentful Paint (LCP) element.

LCP Element in DebugBear

Slow loading of this LCP element not only causes a layout shift, but also results in a poor LCP score. Fixing the font loading issue improves both metrics.

Run A Free Page Speed Test

Test Your Website:

  • No Login Required
  • Automated Recommendations
  • Google SEO Assessment

Identifying the Problem Font

To fix the layout shift, we first need to identify which font is causing the issue. In our example, inspecting the main page text in the Elements panel of Chrome DevTools shows that it uses the "Victor Mono" web font, with "Comic Sans MS" as a fallback.

Inspecting the main text in Chrome DevTools

Looking at the font face declaration for "Victor Mono", we see it uses the font-display: block declaration. This means the text will be invisible until the font loads.

@font-face {
font-family: "Victor Mono";
src: url("victor-mono.woff2") format("woff2");
font-display: block;
}

While this avoids a flash of unstyled text (FOUT), it causes a flash of invisible text (FOIT) and delays the main page text from becoming visible.

Using font-display: swap

In this example, the first step is to remove the flash of invisible text by indicating to the browser that it should display the fallback font while the web font is downloading.

To do this, we change font-display: block to font-display: swap in the font face declaration. This tells the browser to display the fallback font immediately, then swap to the web font once the web font loads.

@font-face {
font-family: "Victor Mono";
src: url("victor-mono.woff2") format("woff2");
font-display: swap;
}
tip

If it aligns with your brand vision and identity, you can use font-display: optional instead. This indicates that the web font is not critical to the page. In certain cases, when using font-display: optional, the browser may choose to not use the web font at all.

With font-display: swap, the main page text - which is also the LCP element, is visible immediately using the fallback font. When the "Victor Mono" font loads, it's swapped in.

This is a good compromise between displaying text quickly and using the desired web font. The swap is less jarring than a FOIT, and the main page text is visible immediately, improving LCP.

Choosing a Better Fallback Font

One way to reduce the layout shift is to choose a fallback font that better matches the size and metrics of the web font.

Poor Fallback Font and good fallback font

In the example page, "Comic Sans MS", or even Brush Script as shown in the previous image, are both poor fallback fonts for "Victor Mono", causing a large shift when the web font loads.

By changing the fallback font so it better matches the web font, we can reduce the size of the layout shift when the web font loads.

"Victor Mono" is a monospaced font, so the first step is to choose a monospaced system font as the fallback. "Courier New" is a good choice:

.web-font {
/* `monospace` is a generic monospaced font family */
font-family: "Victor Mono", "Courier New", monospace;
}

Adjusting Font Metrics

Even with a good fallback font and font-display: swap, there may still be small layout shifts when the web font loads due to differences in font metrics.

To further reduce such layout shifts, we can use font face descriptors to make the fallback font better match the web font.

This could involve using the size-adjust, ascent-override, and descent-override properties in a separate @font-face rule for the fallback font.

First, we need to get the metric values for the web font:

  1. Navigate to Capsize and select the "Victor Mono" font or upload the font file.

    Capsize

  2. Pay particular attention to the "Ascender", "Descender" and "Em Square" values.

  3. Create a @font-face rule for the fallback font, using the size-adjust, ascent-override, and descent-override properties.

@import url("/victor-mono.css");

@font-face {
font-family: "My fallback font";
/* Courier New closely matches Victor Mono */
src: local("Courier New");

/* The fixes! */
/* formula = 1100 / 10 = 110% */
ascent-override: 110%;

/* formula = 250 / 10 = 25% */
descent-override: 25%;
}

.web-font {
font-family: "Victor Mono", "My fallback font";
}

With these adjustments, the fallback font should be a very close match to the web font, minimizing any layout shift when the swap occurs.

Fallback font generator

You can also use a tool like Fallback Font Generator to tweak the fallback font through a visual interface.

Fallback Font Generator

Exercise for the reader

While the above steps can help reduce layout shifts caused by web fonts, the request waterfall shown in the speed test of the demo page highlights an issue of sequential request chains:

Sequential Request Chains

Your task is to think about how you'd improve the font loading performance by optimizing the request chains. For example, do the CSS files need to use @import or can they be inlined?

Conclusion

Layout shifts caused by web fonts can be an issue for user experience and Core Web Vitals scores. By choosing a good fallback font, using font-display: swap, and using font face descriptors, you can minimize such layout shifts and provide a better experience for your users.

If you're working on improving Cumulative Layout Shift and other Core Web Vitals, a monitoring service like DebugBear can help you keep track of your progress and identify new optimizations.

Monitor Page Speed & Core Web Vitals

DebugBear monitoring includes:

  • In-depth Page Speed Reports
  • Automated Recommendations
  • Real User Analytics Data

Get a monthly email with page speed tips