DEV Community

Masa Kudamatsu
Masa Kudamatsu

Posted on • Edited on

Loading Google Fonts and any other web fonts as fast as possible in early 2021

This article summarises a well-cited article by Roberts (2020), who proposes the fastest way of serving Google Fonts via its server. Plus, based on my own experience, I claim that the same technique should apply to any other web fonts as well.

TL;DR

If you use, say, Poppins from Google Fonts, add the following snippet to the <head> element:

<link rel="preconnect" href="https://fonts.gstatic.com" />
<link
  rel="preload"
  as="style"
  href="https://fonts.googleapis.com/css2?family=Poppins&display=swap"
/>
<link
  rel="stylesheet"
  href="https://fonts.googleapis.com/css2?family=Poppins&display=swap"
  media="print"
  onload="this.media='all'"
/>
<noscript>
  <link
    rel="stylesheet"
    href="https://fonts.googleapis.com/css2?family=Poppins&display=swap"
  />
</noscript>
Enter fullscreen mode Exit fullscreen mode

If you have purchased webfonts from a font foundry:

  • Replace https://fonts.gstatic.com in the first line of the snippet above with the URL of a web font server of the font foundry
  • Replace the href attribute values for all the <link> tags with the URL of a stylesheet the font foundry gives you.

Motivation

When I first learned how to use Google Fonts, back in 2018, all I needed to code in the <head> element was as simple as something like this:

<link
  rel="stylesheet"
  href="https://fonts.googleapis.com/css2?family=Poppins&display=swap"
/>
Enter fullscreen mode Exit fullscreen mode

Since then, the technique to speed up the loading of Google Fonts (and other web fonts) has evolved a lot. Writing specifically about Google Fonts, Roberts (2020) provides the definitive answer, backed by evidence and including the fallback code for old browsers and those with JavaScript disabled. His article is widely cited (e.g. by Coyier 2020 and Kurtuldu et al. 2020).

I follow his snippet for my little webapp using Poppins from Google Fonts. It does speed up the site loading.

I also realize that the logic of Roberts's (2020) proposal is not specific to Google Fonts. It can apply to any web fonts. So I try it with another little app of mine that uses web fonts purchased from a font foundry. And voila, it speeds up the site loading as well.

So let me share how to serve web fonts in the fastest speed as of early 2021, step by step.

Step 1: Preconnect the web font server

Start with

<link rel="preconnect" href="https://fonts.gstatic.com" />
Enter fullscreen mode Exit fullscreen mode

If you have used Google Fonts recently, this line of code should be familiar to you. This is what Google Fonts suggests after you select a font today, in addition to the standard <link> tag to refer to the font stylesheet.

This line of code establishes a connection to the web font server early during the page loading, rather than starting a connection after finding a web font file URL in a stylesheet. Mihajlija (2019) and Google Developers (2020) both explain what the <link rel="preconnect"> does in detail.

This is a big deal. To serve web fonts, you’ll tell the browser to get connected not only to your own website server but also to the web font stylesheet server and to the web font file server. But the web font file server’s URL can only be found in the web font stylesheet. So it takes quite a bit of time before the browser starts accessing the web font file server. The preconnect link tag speeds up this process by telling the browser to start accessing the web font file server before reading the web font stylesheet.

For this reason, it should come at the top of your code for serving web fonts.

We have so far talked about Google Fonts only. In principle, however, the same technique should be applicable to any web fonts. The only issue is where to find the font server URL.

From the font foundry you have purchased webfonts, you should have received the <link> tag snippet to be included in the <head> element. Look at the href value. Copy and paste it onto the browser’s address bar and hit the return key. You will see the content of a font stylesheet, starting with @font-face. Using Google Fonts as an example, it’s something like:

@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/poppins/v15/pxiEyp8kv8JHgFVrJJfecnFHGPc.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
Enter fullscreen mode Exit fullscreen mode

See the src property. Its value specifies the web font file URL. Copy the URL up to the first forward slash. In the above example. it’s https://fonts.gstatic.com. That’s the font file server URL.

Step 2: Preload the web font stylesheets

Next line of code is something like this:

<link
  rel="preload"
  as="style"
  href="https://fonts.googleapis.com/css2?family=Poppins&display=swap"
/>
Enter fullscreen mode Exit fullscreen mode

Replace the href attribute value with the one in the <link> tag snippet given by Google Fonts or other font foundries.

This line of code loads the web font stylesheet asynchronously. It means that the browser starts downloading the stylesheet without blocking any other operations specified in the HTML code below. Weiss (2016) explains what preload does in more detail.

This is a big deal as well. With the standard way of loading the font stylesheet with the <link rel="stylesheet"> tag, the remaining lines of code in the HTML document will not be executed until the stylesheet is fully downloaded. This clearly delays the painting of a webpage.

Again, the logic is not specific to Google Fonts. Any web fonts can benefit from “preloading” the font stylesheet.

As a footnote, Djirdeh (2020) recommends using the preload for font files themselves. I tried this approach, but with many font files, the gain in page load speed wasn’t really noticeable. The use of preconnect for the font file server appears to be better.

One caution: the preload loads the stylesheet, but does not read it. In other words, you need to include the standard <link rel="stylesheet"> tag as well as the <link rel="preload"> tag (Chalaris 2019).

But the fallback code in Step 3 below will play the role of reading the stylesheet.

Step 3: Fallback for old browsers

The <link rel="preload"> tag is a fairly recent feature. As of January 2021, the compatible browsers account for over 88% of global page views (Can I Use 2021). Those incompatible browsers will simply ignore the <link rel="preload"> tag (Yobo 2017).

To support the remaining 12% of global page views, Roberts (2020) suggests using the “print media toggle” approach, first proposed (or popularized) by Jehl (2019):

<link
  rel="stylesheet"
  href="https://fonts.googleapis.com/css2?family=Poppins&display=swap"
  media="print"
  onload="this.media='all'"
/>
Enter fullscreen mode Exit fullscreen mode

As before, replace the href attribute value with the one in the <link> tag snippet given by Google Fonts or other font foundries.

Jehl (2019) explains what this code does succinctly:

To start, the link's media attribute is set to print. “Print” is a media type that says, “apply this stylesheet’s rules for print-based media,” or in other words, apply them when the user tries to print the page. Admittedly, we want our stylesheet to apply to all media (especially screens) and not just print, but by declaring a media type that doesn’t match the current environment, we can achieve an interesting and useful effect: the browser will load the stylesheet without delaying page rendering, asynchronously! That’s helpful, but it’s not all we want. We also want the CSS to actually apply to the screen environment once it loads. For that, we can use the onload attribute to set the link's media to all when it finishes loading.—Jehl (2019)

So it does the same thing as the <link rel="preload"> tag.

But it performs slightly worse, as shown by Roberts (2020). I myself experimented with this fallback code, instead of the <link rel="preload"> tag, and the Lighthouse audit score was slightly lower.

Still, it’s certainly better than the standard <link rel="stylesheet">, as shown by Roberts (2020). I think we should include this line of code for every project, to support the widest range of browsers.

If you decide to ignore old browsers, then make sure that you do include the standard <link rel="stylesheet">. As mentioned in Step 2, the <link rel="preload"> tag alone does not read the stylesheet to render web fonts.

Step 4: Fallback for JavaScript-disabled users

Roberts (2020) suggests one more fallback to cover JavaScript-disabled users:

<noscript>
  <link
    rel="stylesheet"
    href="https://fonts.googleapis.com/css2?family=Poppins&display=swap"
  />
</noscript>
Enter fullscreen mode Exit fullscreen mode

Again, replace the href attribute value with the one in the <link> tag snippet given by Google Fonts or other font foundries.

According to Roberts (2020), the print media toggle approach in Step 3 above won’t work with Javascript-disabled browsers. To provide the same experience to such users, we need this snippet. Note that the <noscript> tag will be ignored by JavaScript-enabled browsers (MDN Contributors 2020).


That’s all! It took severa months for me to fully grasp this topic. I don't want you to repeat the same. Hopefully this article helps you understand the web font serving technique more quickly than I did.

Do have a look at Roberts (2020). He explains in detail why each step is necessary, with pieces of evidence on how much the page loading speeds up with each step. The article is very long, but it should be easier to understand after learning the conclusion with my article.

And try the same approach for your purchased web fonts. Let me know whether it works for you or not. If you run a font foundry, let me know if this solution doesn’t work with your web fonts.

References

Can I Use (2021) “Resource Hints: preload”, caniuse.com, accessed on Feb 1, 2021.

Chararis, Angelos (2019) “An answer to ‘Preloading Google Fonts’”, Stack Overflow, Jul. 2, 2019.

Coyier, Chris. (2020) “The Fastest Google Fonts”, CSS-Tricks, May 22, 2020.

Djirdeh, Houssein (2020) “Prevent layout shifting and flashes of invisibile text (FOIT) by preloading optional fonts”, web.dev, May 18, 2020.

Google Developers (2020) “Preconnect to required origins”, web.dev, May 6, 2020.

Jehl, Scott (2019) “The Simplest Way to Load CSS Asynchronously”, Filament Group, Jul. 19, 2019.

Kurtuldu, Mustafa, Thomas Steiner, Dave Crossland, and Roel Nieskens (2020) “Introduction to variable fonts on the web”, web.dev, Aug. 17, 2020

MDN Contributors (2020) “<noscript>”, MDN Web Docs, Dec 16, 2020.

Roberts, Harry. (2020) “The Fastest Google Fonts”, CSS Wizardry, May 19, 2020.

Weiss, Yoav (2016) “Preload: What Is It Good For?”, Smashing Magazine, Feb. 26, 2016.

Yobo, El (2017) “A comment to an answer to ‘How exactly does link rel=“preload” work?’”, Stack Overflow, Feb. 19, 2017.

Top comments (2)

Collapse
 
cuccagna profile image
cuccagna • Edited

But with your solution, browsers that supports preload download two times the font or not? Because if the preload is supported the second link tag (the fallback) is still executed. What do you think abaout?

Collapse
 
thetwopct profile image
James Hunt

Any thoughts on using cross origin?