Making Google Fonts Faster⚡

Photo by Bob Newman on Unsplash (cropped)

If you use Google Fonts on your website or web application, a few additional steps can lead to much faster load times. In this article, I will show you how to:

  1. Skip over some of the latency time for downloading fonts from Google Fonts
  2. Self-host your fonts for faster speed and greater control over FOIT and FOUT
  3. Do the same as #2 but more quickly with a cool tool

But Why?

Google Fonts is hosted on a pretty fast and reliable content delivery network (CDN), so why might we consider hosting on our own CDN?

Let’s take a step back and look at what is happening when you request from Google Fonts using a standard <link> copied from their website:

Did you notice that the link is for a stylesheet and not a font file? If we load the link’s href into our browser, we see that Google Fonts loads a stylesheet of @font-face declarations for all the font styles that we requested in every character set that is available. Not all of these are used by default, thankfully.

Then, each @font-face declaration tells the browser to use a local version of the font, if available, before attempting to download the file from fonts.gstatic.com:

So what’s the problem?

First, we have a minimum of 2 separate requests to different hosts — first for the stylesheet at fonts.googleapis.com, and then to a unique URL for each font hosted at fonts.gstatic.com. This makes it impossible to take advantage of HTTP/2 multiplexing or resource hints.

You may be asking yourself, “Why can’t I just use the direct link to the font?” Google Fonts are updated often so you might find yourself trying to load a font from a link that no longer exists pretty quickly. 🤦🏾

The second problem we encounter with Google Fonts is that we have no control over flash-of-invisible-text (FOIT) and flash-of-unstyled-text (FOUT) while fonts are loading. Setting the font-display property in the @font-face would give us that control, but it’s defined in the Google Fonts stylesheet.

FOIT in action — note the missing navbar text in the filmstrip screenshot (throttled to slow 3G)

Finally, while rare, if Google Fonts is down, we won’t get our fonts. If our own CDN is down, then at least we are consistently delivering nothing to our users, right? 🤷🏻️

If you do nothing else, at least preconnect…

The only basic performance improvement we can do with Google Fonts hosting is warming up the DNS lookup, TCP handshake, and TLS negotiation to the fonts.gstatic.com domain with preconnect:

Why? If you don’t warm up the connection, the browser will wait until it sees the CSS call font files before it begins DNS/TCP/TLS:

Loading Google Fonts without preconnect

This is wasted time because we KNOW that we will definitely need to request resources from fonts.gstatic.com. By adding the preconnect, we can perform DNS/TCP/TLS before the socket is needed, thereby moving forward that branch of the waterfall:

Loading Google Fonts with preconnect to fonts.gstatic.com

Even better: self-host for full control

It would be even better if we had full control over our font files, loading, and CSS properties. Luckily, Mario Ranftl created google-webfonts-helper which helps us do exactly that! It is an amazing tool for giving us font files and font-face declarations based on the fonts, charsets, styles, and browser support you select.

Step 1: Use google-webfonts-helper to download our fonts and provide basic CSS font-face declarations

First, select the Google font you need from the left sidebar. Type in the search box for a filtered list (red arrow), then click on your font (blue arrow):

Step 1: Select a font.

Next, select your character sets and styles. Remember that more styles mean more for the client to download:

Select your character sets and styles (weight and style).

Different fonts have different levels of character support and style options. For example, Open Sans supports many more charsets than Muli:

Open Sans supports many more character sets including Cyrillic, Greek, Vietnamese, and extended sets.

Your final choice is which browsers you want to support. “Modern Browsers” will give you WOFF and WOFF2 formats while “Best Support” will also give you TTF, EOT, and SVG. For our use case, we chose to only host WOFF and WOFF2 while selecting system fonts as fallbacks for older browsers. Work with your design team to decide the best option for you.

Select “Best Support” for all file formats or “Modern Browsers” for only WOFF and WOFF2.

After selecting a browser support option, copy the provided CSS into your stylesheet near the beginning of your stylesheets before you call any of those font families. We choose to put this at the top of our variables partial when using SCSS. You can customize the font file location — the default assumes ../fonts/.

Finally, download your files. Unzip them, and place them in your project in the appropriate location.

Step 2: Loading Optimization

So far, we have only moved where we are hosting files from Google’s servers to ours. This is nice, but not good enough. We want our font files to start downloading right away, not after the CSS is parsed and the CSSOM is created.

We can do this with the preload resource hint:

Preload is a declarative fetch, allowing you to force the browser to make a request for a resource without blocking the document’s onload event.
— from “Preload, Prefetch And Priorities in Chrome” by Addy Osmani

Warning: Before we go any further, make sure you understand that preload will load a resource whether you use it or not. Only preload resources that are needed on a particular page.

How do we choose which file type to preload? Resource hints are not available in every browser, but all the browsers that support preload also support WOFF2 so we can safely choose only WOFF2.

In your HTML file, add resource hints for all WOFF2 font files you need for the current page:

Let’s break down our preload <link> element:

  • rel="preload" tells the browser to declaratively fetch the resource but not “execute” it (our CSS will queue usage).
  • as="font" tells the browser what it will be downloading so that it can set an appropriate priority. Without it, the browser would set a default low priority.
  • type="font/woff2 tells the browser the file type so that it only downloads the resource if it supports that file type.
  • crossorigin is required because fonts are fetched using anonymous mode CORS.

So how did we do? Let’s take a look at the performance before and after. Using webpagetest.org in easy mode (Moto G4, Chrome, slow 3G), our speed index was 4.147s using only preconnect, and 3.388s using self-hosting plus preload. The waterfalls for each show how we are saving time by playing with latency:

Loading from Google with preconnect to fonts.gstatic.com
Self-hosting fonts and using preload

Step 3: Fix FOIT and FOUT (optional)

Different people have different opinions on FOIT (flash of invisible text) and FOUT (flash of unstyled text). For the most part, we prefer to show text as fast as possible even if that means a pesky transition to our preferred font once it loads. For strongly branded content, you may want to keep a FOIT over showing off-brand fonts.

If you’re okay with FOUT, or flash of unstyled text, then we can fix FOIT by adding font-display: swap; to our @font-face declarations.

Check out all your font-display options in this fun Glitch playground by Monica Dinculescu.

subfont

So what if you don’t want to go through all of these steps? The subfont npm package will do this in addition to dynamically subsetting your fonts at build. It takes some more set-up time, but it’s definitely worth a try.

Are you a fan of Gatsby? There’s even a subfont plugin for it.

Additional Considerations

Host static assets on a CDN

One thing Google Fonts does offer is a fast and reliable content delivery network (CDN). You should also host your static assets on a CDN for faster delivery to users in different regions. We use AWS S3 plus Cloudfront, the CDN service offered by Amazon, but many options exist.

Size and Popular Fonts

In some of my tests for our company website, I noticed smaller font file sizes for some fonts hosted by Google. My theory is this is due to Google’s variants for optimization:

Google Fonts maintains 30+ optimized variants for each font and automatically detects and delivers the optimal variant for each platform and browser.
— from Web Font Optimization by Ilya Grigorik

In addition, very popular fonts like Open Sans and Roboto are likely to exist in your users’ cache. Hopefully, in a future post I can explore HTTPArchive data and give you an idea for which fonts are the most popular.

So, before you commit to a path of self-hosting, compare the tradeoffs of byte sizes and speed/control.

Want to see all the sample code and performance results? Here is the repo.

Resources you should checkout