Zach’s ugly mug (his face) Zach Leatherman

The Web Fonts: Preloaded

April 05, 2016 On Twitter (archived)

Summary: If you’re not currently using a font loading strategy, using preload with web fonts will reduce the amount of FOIT visitors will see when they visit your site—paid for by sacrificing initial render time. Don’t preload too much or the cost to initial render will be too high. For devs using a font loading strategy, the same rules apply. Try to only preload a single web font, whether that be the only font in a single stage load or the subset font in the first stage of a two stage load. Further, preload is an improvement over Data URIs for two stage font loads in supporting browsers, and I will be happy to welcome it as a best practice when its browser support grows.

After the recent release of loadCSS 1.0 updated the utility into a <link rel="preload"> polyfill for CSS and Yoav Weiss’ excellent Smashing Magazine post on preload, I decided to experiment with preload to see if it could improve the variety of web font loading approaches I’ve written about in the past.

Here’s all you need to add to the <head> of your page to start preloading:

<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

via Preload: What Is It Good For? by Yoav Weiss

If you have WOFF2 formats in your @font-face block, make sure you preload the WOFF2 format. In fact, you should probably limit preload to the first format in your @font-face src stack. If you preload a WOFF file and have WOFF2 first in your stack, the browser will download both. This is undesirable.

Benchmarks

Let’s look first at the effect of preload on my own site without any font loading strategy:

(Times generated using Chrome Canary’s Developer Tools Network Throttling in Regular 3G mode)

With <link rel="preload">
No Preload Preload Roman and Preload Italic and Preload Bold and Preload Bold Italic
Initial Render 573ms 795ms
(+38%)
980ms
(+71%)
1.23s
(+114%)
1.38s
(+140%)
Roman Loaded 2.12s 888ms
(-138%)
1.18s
(-44%)
1.42s
(-33%)
1.75s
(-17%)
Italic Loaded 2.12s 1.83s
(-13%)
1.10s
(-48%)
1.33s
(-37%)
1.56s
(-26%)
Bold Loaded 2.20s 1.96s
(-10%)
1.92s
(-12%)
1.46s
(-33%)
1.75s
(-20%)
Bold Italic Loaded N/A N/A N/A N/A 1.63s

Perhaps obviously, the more fonts you preload the more initial render time suffers. It’s even more interesting when you compare to the numbers I ran on Data URIs.

(Times generated using Chrome Canary’s Developer Tools Network Throttling in Regular 3G mode)

Compare preload with Data URI
Default Behavior Inline Roman Data URI Preload Roman
Initial Render 573ms 953ms 795ms
(-16%)
Roman Loaded 2.12s 1.01s 888ms
(-12%)
Italic Loaded 2.12s 2.05s 1.83s
(-10%)
Bold Loaded 2.20s 2.11s 1.96s
(-7%)
Bold Italic Loaded N/A N/A N/A

preload affects initial render less than Data URIs and from a maintenance perspective it operates much cleaner. preload improves the performance of all four drawbacks on listed on the Data URI post:

  1. They don’t directly block render, although as shown above in low bandwidth situations they can delay initial render.
  2. You can add a type attribute to declare the font format to download. Right now only Chrome Canary has a working implementation of this feature and it also supports WOFF2. But this type attribute protects you if a browser implements preload without a newer font format (or vice versa).
  3. Works great with browser cache.
  4. Multiple preloaded fonts load in parallel (although I wouldn’t recommend preloading multiple web fonts).

Best Practice?

If the alternative is doing nothing (please don’t), then yes I would recommend preloading the most often used web font on your site. In the example above, Lato-Regular.woff2 was 25KB. If you preload more file weight (or more fonts), the tradeoff in initial render time might make it more difficult to accept.

Use with a Font Loading Strategy

preload isn’t a panacea because it’s not sufficient by itself as a font loading strategy. There are two major considerations to font loading: (1) Eliminating the Flash of Invisible Text (FOIT) by showing a Flash of Unstyled Text (FOUT) and (2) Speeding up font loading to minimize the amount of time that fallback text is shown. We want to reduce the jarring reflows that happen when content is re-rendered with our new, shiny web fonts. An ideal strategy would eliminate both FOIT and FOUT.

preload helps our second point but does nothing for the first. We still need to implement a FOUT strategy—of course, my favorite is still Critical FOFT with an inline Data URI for the first stage. This strategy has shown to eliminate FOIT and FOUT, but at a cost documented above (and in the Data URI post). Let’s see how preload plays out there:

(Times generated using Chrome Canary’s Developer Tools Network Throttling in Regular 3G mode)

2-Stage Font Loading Strategies
Critical FOFT Critical FOFT Roman Data URI Critical FOFT preload
Initial Render 588ms
 
58.6KB HTML
619ms
(+5%)
65.7KB HTML
675ms
(+14%)
58.6KB HTML
Stage 1 Render
(Critical Roman)
1.04s 619ms
(-40%)
675ms
(-35%)
Stage 2 Render
(Roman, Italic, Bold, Bold Italic)
2.57s 2.44s
(-5%)
2.29s
(-10%)

The results are pretty good for a Two Stage font loading approach. If your web font requirements are a little simpler and you’re only loading a single web font (One Stage font loading), then preload will have a similar beneficial performance gain. However, if you’re loading multiple web fonts in a grouped load (again, One Stage) with a single repaint/reflow step, preload isn’t wise: if you preload one of the fonts, the repaint/reflow will not happen until all web fonts have completed and it will be wasted; if you preload all of them, the sacrifices to initial render are too costly.

Conclusion

The benefits to preload for fonts are numerous—especially over the Two Stage Data URI approach. The only nail in the preload coffin now is browser support. Once browser support for this is better, I will definitely switch from using Data URIs in the first stage of Critical FOFT to simply preloading the hosted first stage WOFF2 file (or similarly if you’re only loading a single web font). Always measure the sacrifice in initial render time to determine if this trade-off is worth it for your site.


< Newer
Web Fonts for President 2016
Older >
Trying out a new Font Stack

Zach Leatherman IndieWeb Avatar for https://zachleat.com/is a builder for the web at IndieWeb Avatar for https://fontawesome.com/Font Awesome and the creator/maintainer of IndieWeb Avatar for https://www.11ty.devEleventy (11ty), an award-winning open source site generator. At one point he became entirely too fixated on web fonts. He has given 84 talks in nine different countries at events like Beyond Tellerrand, Smashing Conference, Jamstack Conf, CSSConf, and The White House. Formerly part of CloudCannon, Netlify, Filament Group, NEJS CONF, and NebraskaJS. Learn more about Zach »

10 Reposts

IndieWeb Avatar for https://codedigger.caIndieWeb Avatar for https://www.yazoogle.com.auIndieWeb Avatar for https://css-tricks.comIndieWeb Avatar for https://codestream.tkIndieWeb Avatar for https://softwaremile.comIndieWeb Avatar for https://711web.comIndieWeb Avatar for https://docuneedsph.comIndieWeb Avatar for https://allprowebdesigns.comIndieWeb Avatar for http://ddrv.cnmanuboss
3 Comments
  1. Richard Fink Disqus

    24 Jun 2016
    Like your advice, Zach. You don't hedge. "Try to only preload a single web font"Clear advice. Thanks.https://twitter.com/FontFri...https://www.facebook.com/fo...https://richardfink.github....
  2. robertmodel Disqus

    08 Jun 2017
    whats the deal with the menu explosion? trying to hint someting?
    1. zachleat Disqus

      08 Jun 2017
      what’s the deal with airline food??
Shamelessly plug your related post

These are webmentions via the IndieWeb and webmention.io.

Sharing on social media?

This is what will show up when you share this post on Social Media:

How did you do this? I automated my Open Graph images. (Peer behind the curtain at the test page)