Avoid Layout Shifts Caused by Web Fonts With PostCSS Fontpie
Tags: code, fonts, javascript, performance
Published: 2024-05-10 15:59:18

---
title: Avoid Layout Shifts Caused by Web Fonts With PostCSS Fontpie
published: true
date: 2023-05-24 00:00:00 UTC
tags: code,fonts,javascript,performance
canonical_url: https://tomeraberba.ch/avoid-layout-shifts-caused-by-web-fonts-with-postcss-fontpie
---

[*You can also read this post on my website!*](https://tomeraberba.ch/avoid-layout-shifts-caused-by-web-fonts-with-postcss-fontpie)

When your CSS references a web font before it finishes downloading, the browser renders text using a fallback system font instead, causing a [layout shift](https://web.dev/cls) if the text container’s height changes once it’s rendered with the web font.

[Optimizing your font files](https://simonhearne.com/2021/layout-shifts-webfonts#optimise-font-files) and using an [intelligent font loading strategy](https://simonhearne.com/2021/layout-shifts-webfonts#deliver-your-fonts-fast) can eliminate layout shifts, but only if the web font is not immediately used on the page. Otherwise you have to ensure the text container’s height doesn’t change. [Fontpie](https://github.com/pixel-point/fontpie) can help with this. It’s a tool for generating CSS that adjusts a fallback font’s metrics so it takes up the same amount of space as your web font. The result is no layout shifts even if the font is immediately used!

Part of what makes Fontpie great is that it’s framework agnostic, but that also means it’s a bit manual to use and I wanted something I could easily integrate into this website’s build. I was already using [PostCSS](https://github.com/postcss/postcss) so I decided to make a Fontpie PostCSS plugin. The result is [`postcss-fontpie`](https://github.com/TomerAberbach/postcss-fontpie). And now generating fallback font metrics for my web fonts is as easy as adding the following to my [PostCSS config](https://github.com/TomerAberbach/website/blob/main/postcss.config.js):

**postcss.config.js**

```js
const { join } = require(`path`)

module.exports = {
  plugins: [
    // ...
    require(`postcss-fontpie`)({
      fontTypes: {
        dm: `mono`,
        'Kantumruy Pro': `sans-serif`,
      },
      srcUrlToFilename: url => join(__dirname, `src/styles`, url),
    }),
    // ...
  ],
}
```

You can see the generated fallback font metrics in [this website’s CSS](https://tomeraberba.ch/build/_assets/fonts-6XEYXKJX.css) and their effects in the following before-and-after GIFs:

<video aria-label="This website's web font loading and causing a layout shift" aria-roledescription="gif" autoplay="" loop="" muted="" playsinline="" role="img"><source src="https://tomeraberba.ch/build/_assets/without-postcss-fontpie-62AUO4YV.webm" type="video/webm"></source><source src="https://tomeraberba.ch/build/_assets/without-postcss-fontpie-V3P3LCDI.mp4" type="video/mp4"></source></video>

<video aria-label="This website's web font loading without causing a layout shift" aria-roledescription="gif" autoplay="" loop="" muted="" playsinline="" role="img"><source src="https://tomeraberba.ch/build/_assets/with-postcss-fontpie-GXTNJQFK.webm" type="video/webm"></source><source src="https://tomeraberba.ch/build/_assets/with-postcss-fontpie-3QOJWHZG.mp4" type="video/mp4"></source></video>

Check out [`postcss-fontpie`’s usage example](https://github.com/TomerAberbach/postcss-fontpie#usage) to use it in your own website!