Loading Web Fonts Without Performance Penalty From Lighthouse

One thing that will most certainly lose you performance points in Google Lighthouse Performance Audit is loading web fonts. More specifically, loading web fonts in a way that render-blocks.

If you simply drop @font-face into your CSS or load <link rel="stylesheet" ... /> tags into your <head/>, Google Lighthouse will hate you. Even if you are loading a Google Font.

Don’t despair! It’s very easy to avoid this penalty.

Step 1: Skip the <link/>

To avoid render-blocking, don’t just add the default <link .../> or @import { ... } code that Google Fonts gives you to your site. Google Fonts gives you a link to a stylesheet which loads the fonts. We want to skip this interim step and load the content of that stylesheet directly.

So for example if I want to load the font Raleway, Google gives me:

<link href="https://fonts.googleapis.com/css?family=Raleway" rel="stylesheet">

So I load the URL https://fonts.googleapis.com/css?family=Raleway in my browser and get its contents.

The CSS file contains all of the @font-face { ... } rules for loading my font. I’m going to copy them into my site’s CSS.

Step 2: Setup Font Swapping

Now that we’re loading the fonts directly via @font-face { ... } rules in our own CSS file, we need to instruct the browser to how to handle the font before it is fully-loaded. We use the font-display CSS rule for that.

Setting font-display: swap; tells the browser to use the closest matching font in the font stack, and then swap in the web font after it loads. Setting font-display: optional; tells the browser to use the closest matching font in the font stack that is currently available, or is available within 100ms of page load. In other words, the web font will not be swapped-in if it is not almost immediately available.

What’s the downside? The font-display property doesn’t have great cross-browser support,and the default behavior varies from browser to browser. On most browsers the default behavior will be FOUT: a flash of unstyled text,while the browser displays the closest matching font, and then loads the web font when it becomes available. This experience can be a little jarring.

If you use font-display: swap; and your user’s browser supports it, your users will experience FOUT before the font loads for the first time. After the font is loaded and cached, it will be used immediately.

If you use font-display: optional; users whose browser supports the property will not notice FOUT, but they may experience a page rendered in the closest matching font in the stack when the web font is not immediately available. On subsequent loads (when the web font is cached), pages will render immediately using the web font.