SvelteKit Fontaine: Reduce Custom Font CLS
Tags: sveltekit, css, webdev
Published: 2023-07-10 09:59:51

---
title: "SvelteKit Fontaine: Reduce Custom Font CLS"
published: "true"
description: "SvelteKit Fontaine ✍🏽 how to eliminate or reduce font swap cumulative layout shift working with custom, self-hosted fonts in ❤️ SvelteKit."
tags: "sveltekit, css, webdev"
canonical_url: "https://rodneylab.com/rust-cloudflare-worker-logging/"
cover_image: "https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a637f83265yk64ox9413.png"
---

## 🏄🏽 Font Swap CLS

In this post, we see how you can use SvelteKit with **Fontaine** to reduce Cumulative Layout Shift (**CLS**) by **up to 100%**, when working with custom or self-hosted fonts.  We first look at how the problem arises, then turn to a solution, using Fontaine.  If that&rsquo;s what you came here for, then let&rsquo;s roll our sleeves up!

We focus on SvelteKit here, and use Fontaine to solve the problem.  Our solution relies on Vite support, so the same approach should work just fine with Astro, for example.  Though if you are working with **Astro**, or want to know how Fontaine works under the hood, see the recent <a href="">article on reducing Astro font swap CLS using Capsize</a>.

## 🤔 Problem: Ensuring Text Remains Visible during Webfont Load

When running Lighthouse web development tooling, if your site uses webfonts or Google fonts, you might get the suggestion:  &ldquo;Ensure text remains visible during webfont load&rdquo;.  This is because text might well be invisible, on a slow connection, while the browser loads the webfont.  Somehow making the text visible, even in a font other than the preferred one, will improve user experience, making the page appear to load quicker.

## 🫣 Solution: Set `font-display: swap`
The advice offered on the <a href="https://developer.chrome.com/docs/lighthouse/performance/font-display/" />Chrome Developers site, to ensure the font remains visible, is to use the `@font-face` `font-display: swap` directive</a>.  Browsers will have some fonts available by default.  Typically, Times New Roman and Arial are included in this list, though for Android devices, Roboto is your safe default.

Setting the `font-display: swap` directive instructs the browser to display the fallback font, instead of the webfont, whenever the webfont is not available quickly.  Then, once the webfont has fully downloaded the browser swaps out the fallback font with the webfont.  Typically, you will set Arial as the fallback for sans fonts and Times New Roman for serif.  Then, include Roboto as a second fallback for both (serif and sans-serif), to cover Android devices.

## 😬 New Problem: Font Swap introduces Layout Shift

![SvelteKit Fontaine: text rendered in the fallback Arial font with the words compiled, compact and complete able to fit on just two lines.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i3u9pg7tig5yvi2uwymj.png)

![SvelteKit Fontaine: text rendered in the webfont font with the words compiled, compact and complete needing to be spread over three lines.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zmbsd52c7q4ri92l2kng.png)

Our approach improves user experience, making the page load faster.  However, it introduces a side effect: layout shift.  Fonts have different metrics &mdash; the height of a capital letter, how far glyphs like `l` and `g` ascend or descend, and so on.  Using the default values for these metrics, for the fallback font, will typically result in a layout shift, when the browser replaces the fallback with the actual webfont.  Let&rsquo;s see how Fontaine can help!

## 🎁 Final Solution

Fontaine has metrics for common webfonts, it sources them from the <a href="https://rodneylab.com/svelte-capsize-styling/">Capsize typography tooling</a>.  Using modern CSS, it can override the layout of the fallback font.  This might make it look a little more compact or stretched out (depending on font relative sizes), than normal.  However, this layout override results in zero, or very little layout shift when the browser swaps fonts during page load.

Using modern CSS, Fontaine adds overrides for the fallback fonts.  We will see how to configure it in the next section.  Below, is the code generated by Fontaine for the Overpass webfont with Arial and Roboto as fallbacks.

```css
:root {
  /* TRUNCATED... */
  --font-family: "Overpass", "Overpass fallback";
    /* TRUNCATED... */
}
@font-face {
  font-display: swap;
  font-family: Overpass;
  font-style: normal;
  font-weight: 400;
  src: url(../../../fonts/overpass-v12-latin-regular.woff2) format("woff2");
}
@font-face {
  font-family: Overpass fallback;
  src: local("Roboto");
  size-adjust: 100.5896%;
  ascent-override: 87.7824%;
  descent-override: 38.0755%;
  line-gap-override: 0%;
}
@font-face {
  font-family: Overpass fallback;
  src: local("Arial");
  size-adjust: 100.7009%;
  ascent-override: 87.6854%;
  descent-override: 38.0334%;
  line-gap-override: 0%;
}
  /* TRUNCATED... */
```

In line `3`, Fontaine has added `Overpass fallback` to the `--font-family` custom property (it was originally `--font-family: "Overpass"`).  As well as that, it has added new `@font-face` directives for Roboto and Arial (lines `13`-`28`).

## ⚙️ SvelteKit Fontaine: Configuration

As it happens, Fontaine configuration is quite straightforward.  We are assuming you self-host fonts in your project and have already included the `font-display: swap` directive in your CSS.  Use the <a href="https://gwfh.mranftl.com/fonts">Google Webfonts Helper by Mario Ranftl to get the CSS snippets for your chosen webfonts</a>, and also download the font WOFF2 files.

1. Add the <code>fontaine</code> package to your SvelteKit project: 
    ```shell
    pnpm add -D fontaine
    ```
2. Update your <code>vite.config.ts</code> file to use the <code>FontaineTransforms</code>:
    ```typescript
    import { sveltekit } from "@sveltejs/kit/vite";
    import { FontaineTransform } from "fontaine";
    import { defineConfig } from "vite";
 
    export default defineConfig({
      plugins: [
        sveltekit(),
        FontaineTransform.vite({ fallbacks: ["Arial", "Roboto"] }),
      ],
    });
    ```
    I picked Arial as a fallback here, as I have a sans webfont.  Roboto is a second fallback, worth including for Android devices.
3. Run your project as normal.  Inspecting CSS source in dev mode, or for a built site running in preview mode, you should be able to find the CSS modifications outlined above.

## 💯 SvelteKit Fontaine: Checking your Work

You can check all is good by building your site and the running Lighthouse on it, locally, in preview mode.  The difference will be most pronounced on mobile.  For the basic layout above, I saw CLS drop from 3% to **zero** when I switched on Fontaine.  Let me know what improvements you get.

## 🙌🏽 SvelteKit Fontaine: Wrapping Up

In this post, we saw why you would want to use Fontaine in your SvelteKit project, as well as how to use it.  More specifically, we saw:

- **what problems Fontaine solves**;
- **how to use Fontaine with Vite** to reduce CLS; and
- how to might check **CLS is actually reduced**.

Please <a aria-label="Open the Rodney Lab Git Hub repo" href="https://github.com/rodneylab/sveltekit-fontaine">see the full repo code on the Rodney Lab GitHub repo</a>. I do hope you have found this post useful and can use the code in your own Svelte project.  Let me know if you have any suggestions for improvements to the post.  Drop a comment below or <a href="https://rodneylab.com/contact/">reach out on other channels</a>.

## 🙏🏽 SvelteKit Fontaine: Feedback

If you have found this post useful, see links below for further related content on this site. I do hope you learned one new thing from the video. Let me know if there are any ways I can improve on it. I hope you will use the code or starter in your own projects. Be sure to share your work on Twitter, giving me a mention, so I can see what you did. Finally, be sure to let me know ideas for other short videos you would like to see. Read on to find ways to get in touch, further below. If you have found this post useful, even though you can only afford even a tiny contribution, please <a aria-label="Support Rodney Lab via Buy me a Coffee" href="https://rodneylab.com/giving/">consider supporting me through Buy me a Coffee</a>.

Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via <a href="https://twitter.com/messages/compose?recipient_id=1323579817258831875">@askRodney</a> on Twitter and also <a aria-label="Contact Rodney Lab via Telegram" href="https://t.me/askRodney">askRodney on Telegram</a>. Also, see <a aria-label="Get in touch with Rodney Lab" href="https://rodneylab.com/contact/">further ways to get in touch with Rodney Lab</a>. I post regularly on <a aria-label="See posts on svelte kit" href="https://rodneylab.com/tags/sveltekit/">SvelteKit</a> as well as <a href="https://rodneylab.com/tags/seo/" aria-label="See posts on search engine optimisation">Search Engine Optimization</a> among other topics. Also, <a aria-label="Subscribe to the   Rodney Lab newsletter" href="https://newsletter.rodneylab.com/issue/latest-issue">subscribe to the newsletter to keep up-to-date</a> with our latest projects.