How to preload fonts on Netlify (issue resolution)
Tags: webdev, frontend
Published: 2023-07-11 09:58:40


On my personal website, I am preloading the fonts [to improve page loading speed](https://web.dev/codelab-preload-web-fonts/) and to prevent [FOUT](https://www.paulirish.com/2009/fighting-the-font-face-fout/). I had noticed that FOUT was still happening sometimes on slower connections and wasn't sure why. When I ran a performance audit of my homepage on [WebPageTest](https://www.webpagetest.org/), I saw in the *Opportunities & Experiments* section that my fonts were *not* being preloaded! Strange! 😕

WebPageTest lists 2 opportunities related to this issue:
1. 2 fonts are hosted on 3rd-party hosts
1. 2 resources are being preloaded, but are not used during page load.

When I drilled into the first item, I saw that the domain of my fonts is *cloudfront.net*. I host my website on Netlify and have my fonts there too. It appears that Netlify moves my font files to another domain and rewrites some of the URLs in the `head` of the webpages when it builds my website.

![Opportunities & Experiments item: 2 fonts are hosted on 3rd-party hosts. It shows the 2 URLs which are](https://www.roboleary.net/assets/img/blog/2023-07-11-preload-fonts-netlify/webpagetest-font-3rd-party.png)

Inspecting my home page in production, the `head` looks as follows:

```html
<head> 

<link rel="preload" href="/assets/fonts/nunito-regular-webfont.woff2" 
as="font" type="font/woff2" crossorigin=""> 

<style>
@font-face{
  font-family:Nunito;
  src :url("https://d33wubrfki0l68.cloudfront.net/bd0f31921c6187f994fbf2b3b22f74a0f3e87b2e/fd58e/assets/fonts/nunito-regular-webfont.woff2") format("woff2");
  font-display:swap
}
</style> 

<!-- other stuff -->
	
</head>
```

**As you can see, the URL in the `link` and the `@font-face` rule do not match.** In my source code, they match! Therefore, Netlify has rewritten the URL in the `@font-face` rule. How can I get Netlify *not* to do this? 😅

## The solution to stop Netlify hosting a font file on a 3rd party domain

Someone else posted a very similiar question -- [Asset optimization - preloading fonts](https://answers.netlify.com/t/asset-optimization-preloading-fonts/3197) -- on this topic on the Netlify Support forum. The Netlify staff say the following:

> The cloudfront URL’s are the result of asset optimization, as configured on your site’s deploy settings page most of the way down.
>
> Things that get optimized (which don’t include the <link> tag at present) will get rewritten to cloudfront URL’s. HOWEVER all content we serve is served from a CDN - that’s just the CDN we use for optimized assets. All traffic from netlify comes from some part of some CDN
>
> If you want things to be consistent, turn off that feature in our UI. But hopefully things work normally, even if they look a little weird in the source code?

The issue is that asset optimization rewrites URLs and they do not include the `link` tag. In the same thread, the support staff member [stated that Netlify do not intend to change this behaviour](https://answers.netlify.com/t/asset-optimization-preloading-fonts/3197/9)!

**The suggested solution is to disable [asset optimization (post processing)](https://docs.netlify.com/configure-builds/file-based-configuration/#post-processing) completely. However, I want to use some facets of asset optimization e.g. minifying JavaScript. Therefore, I would prefer not to disable it.**

Instead, I changed my page template **to produce absolute URLs in the `link` and the `@font-face` rule and it solved the issue!**

I use nunjucks for my page template, and have a custom filter `toAbsoluteUrl` for this task. This is what it looks like if you happen to use nunjucks:

```nunjucks
{% set regularFont = "/assets/fonts/nunito-regular-webfont.woff2" | toAbsoluteUrl %}

<link rel="preload" href={{ regularFont }} 
as="font" type="font/woff2" crossorigin/>

<style>
@font-face {
		font-family: Nunito;
		src: url({{ regularFont }}) format("woff2");
		font-display: swap;
}
</style>
```

Rerunning the test on WebPageTest, I can see that now visual progress is 100% after 1.7 seconds and there is no cumulative layout shift (blue line in graph). Previously it took 2.4 seconds and there was a very minor cumulative layout shift (red line in graph)! 📈

![Graph comparing visual progress metric between 2 runs on WebPageTest. The second run is after I fix the URL issue. You can see that now visual progress is 100% after 1.7 seconds, previously it took 2.4 seconds](https://www.roboleary.net/assets/img/blog/2023-07-11-preload-fonts-netlify/webpagetest-comparison.png)

That may not sound like much, but it mitigates [FOUT](https://www.paulirish.com/2009/fighting-the-font-face-fout/) significantly!