Performance - Font Optimisations

📆 8 March, 2021

⚠️ Common font problems

Each browser has its own default font-loading behaviour.

  • Chrome will hide text for up to 3 seconds. If text is still not ready, uses a system font until font is ready. Swaps out font.\
  • Firefox will hide text for up to 3 seconds. If text is still not ready, uses a system font until font is ready. Swaps out font.
  • Safari hides text until font is ready.
  • Edge uses a system font until font is ready. Swaps out font.

Flash of Invisible Text (FOIT)

https://css-tricks.com/font-display-masses/

Flash of Un-styled Text (FOUT)

https://css-tricks.com/font-display-masses/

FOIT vs FOUT example

Diagram of locally hosted fonts vs externally hosted fonts

💫 Google Fonts

Google has a global CDN that is tuned to deliver content at the highest speed possible. The files they provide are also well compressed.

When using Google Fonts we retrieve font files from Google via 2 network requests:

  1. fonts.googleapis.com - get the @font-face ruleset
  2. fonts.gstatic.com - get the font files (.woff, .woff2 or .ttf etc. dependent on browser)

This means we spend time during page-load connecting to Google and downloading font files from them. This is a render blocking activity that will slow page load. It may also impact what the user sees on the screen e.g. they may see a flash of un-styled text (FOUT) or a blank screen (FOIT) depending on how font-display is handled.

Gatsby has a good guide on how to use Google Fonts here.

✨ Optimising web-font loading

Font types per browser

Web fonts are retrieved from another location during page load. Network request + download.

1️⃣ Preconnect

If we know we are going to need a font from another location than our own domain (e.g. Google Fonts) then it makes sense to let the browser know early to connect to them. This enables the browser to perform DNS resolution, Connect and SSL at the earliest opportunity.

webpagetest.org provide a chart showing when connections occur and what is downloaded.

Preconnect by adding a a link tag in the head of your HTML document e.g.

<link rel="preconnect" href="https://fonts.gstatic.com" />

⚠️ Warning: too many preconnects can defeat the purpose and actually negatively impact performance. A good rule of thumb is to try and limit preconnects to a max of ~5.

2️⃣ Preload

Important resources that will definitely be displayed on the page are useful for the browser to know about and be able to retrieve early in the page load process (preload), before the browsers' main rendering machinery kicks in. This ensures they are available earlier and are less likely to block the page's render, improving performance.

Preload your web font resources by adding a link tag in the head of your HTML document e.g.

<link rel="preload" href="[replace_with_google_fonts_url]" as="font">

Using as to specify the type of content to be preloaded allows the browser to:

  • Prioritize resource loading more accurately.
  • Store in the cache for future requests, reusing the resource if appropriate.
  • Apply the correct content security policy to the resource.
  • Set the correct Accept request headers for it.

See this MDN doc for a list of resource types that can be preloaded.

⚠️ Warning: too many preloads can worsen performance as they block initial render.

3️⃣ Cache

Fonts rarely change so we can cache them for a long period of time.

This can be done by setting the cache-control header for a resource e.g.

"cache-control": [
  {
    value: `public, max-age=${THIRTY_DAY_TIME_TO_LIVE}`,
  },
],

4️⃣ Reduce web font size

Reduce web font size: https://web.dev/reduce-webfont-size/

We can reduce the size of the font file that the browser needs to download by:

  • using a compressed file format e.g. .woff2
  • using a unicode-range that selects only the characters used on the page

⭐ Self-host fonts

1️⃣ Self-hosting fonts in Gatsby ourselves

We might choose to hold the font files within our codebase ourselves without using a third-party plugin to help serve those files.

We can self host fonts by downloading the font files (.woff, .woff2, .tff etc) ourselves. You can use caniuse to check the browser compatibility of each font file format.

In Gatsby we can store the font files in the static folder, a special folder that Gatsby knows to include in the build.

Example: SEO PR - Self-host Open Sans font

2️⃣ Self-hosting fonts in Gatsby using Fontsource

We may decide to let a third-party plugin do the heavy lifting for us such as setting preconnect/preload rules for the fonts and handling how those fonts are loaded.

Gatsby has a useful recipe on how to self-host Google Fonts here.

The Fontsource package comes with a range of fonts that we can import into our layout index.js file. E.g.

npm install @fontsource/open-sans
// layout/index.js

import "@fontsource/open-sans/400.css"
import "@fontsource/open-sans/600.css"
import "@fontsource/open-sans/700.css"

Fontsource populates the static folder for us with our chosen font files (the ones we imported above). Gatsby knows to include those files in the build because they are in the static folder.

Example: SEO PR - use fontsource package for self-hosting fonts

🌟 Web-safe fonts

Web-safe fonts are fonts that are already available on devices, a list of which can be found here.

font-family: Georgia;

This is the most performant of the options as it means the client doesn't need to spend any time executing network requests, downloading fonts and repainting in the browser.

However, the user experience should be considered before choosing this option.

Example: SEO PR - Use Georgia font for headings (previously Libre Baskerville)

Useful tools