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:
- Skip over some of the latency time for downloading fonts from Google Fonts
- Self-host your fonts for faster speed and greater control over FOIT and FOUT
- Do the same as #2 but more quickly with a cool tool
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.
@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.
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? 🤷🏻️
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:
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:
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.
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):
Next, select your character sets and styles. Remember that more styles mean more for the client to download:
Different fonts have different levels of character support and style options. For example, Open Sans supports many more charsets than Muli:
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.
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
Finally, download your files. Unzip them, and place them in your project in the appropriate location.
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.
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.
In your HTML file, add resource hints for all WOFF2 font files you need for the current page:
Let’s break down our preload
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/woff2tells the browser the file type so that it only downloads the resource if it supports that file type.
crossoriginis 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:
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
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.
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.
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.