zachleat’s Ugly Mug

Zach Leatherman

The Web Fonts: Preloaded

05 April 2016 Read in about 6 minutes #9 most popular

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 PreloadPreload Romanand Preload Italicand Preload Boldand Preload Bold Italic
Initial Render573ms795ms
(+38%)
980ms
(+71%)
1.23s
(+114%)
1.38s
(+140%)
Roman Loaded2.12s888ms
(-138%)
1.18s
(-44%)
1.42s
(-33%)
1.75s
(-17%)
Italic Loaded2.12s1.83s
(-13%)
1.10s
(-48%)
1.33s
(-37%)
1.56s
(-26%)
Bold Loaded2.20s1.96s
(-10%)
1.92s
(-12%)
1.46s
(-33%)
1.75s
(-20%)
Bold Italic LoadedN/AN/AN/AN/A1.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 BehaviorInline Roman Data URIPreload Roman
Initial Render573ms953ms795ms
(-16%)
Roman Loaded2.12s1.01s888ms
(-12%)
Italic Loaded2.12s2.05s1.83s
(-10%)
Bold Loaded2.20s2.11s1.96s
(-7%)
Bold Italic LoadedN/AN/AN/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 FOFTCritical FOFT Roman Data URICritical FOFT preload
Initial Render588ms
 
58.6KB HTML
619ms
(+5%)
65.7KB HTML
675ms
(+14%)
58.6KB HTML
Stage 1 Render
(Critical Roman)
1.04s619ms
(-40%)
675ms
(-35%)
Stage 2 Render
(Roman, Italic, Bold, Bold Italic)
2.57s2.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.

Retweet to share this post