When we talk about web performance and especially the Core Web Vitals (CWV), it almost seems like image and JavaScript optimization techniques steal the spotlight.
However, there is another player that shouldn’t be overlooked - web fonts.
Considering that they are often large files that take a while to load and can even block rendering of the text, font optimization is a critical piece of the overall performance strategy.
Typography is also fundamental to good design, branding, readability, and accessibility. And web fonts are the ones making all these things possible.
In the following lines, we’ll see how fonts affect your Core Web Vitals and how you can optimize their loading.
Let’s begin!
There is not a single font optimization technique that can solve all of your problems.
That might be a bit harsh, but it’s the truth. Font loading has been a big culprit of web performance for years now. And all of the current strategies for serving web fonts have significant drawbacks.
For quite some time, if you wanted to serve web fonts, you had to choose between:
Or
Put simply, you could either make your visitors stare at a blank screen or risk unexpected layout shifts occurring on your website.
Both are unacceptable solutions in today’s Core Web Vitals world.
Basically, the font loading situation was:
Then, the font-display property was announced.
font-display tells the browser how it should proceed with text rendering when the associated web font has not loaded. It is defined per font-face.
Browsers have default font-loading behavior when rendering text that uses a font-family that is not yet available:
Source: web.dev
The process of font downloading is divided into three major periods:
Understanding these periods will allow you to use the font-display values more effectively:
Source: How to avoid layout shifts caused by web fonts
When deciding which font-display value to use for your site, a good rule of thumb is this Google recommendation:
As I said earlier, there is still no complete solution that fixes all possible font issues regarding font loading. Although Google itself recommends these steps, that doesn’t mean they are risk-free.
In fact, some of the font-display values can worsen your Core Web Vitals.
Here's the deal:
Some font loading techniques can harm your Core Web Vitals.
For instance, if a font has not been loaded (FOIT), browsers typically delay text rendering (font-display: block). In some cases, this delays the First Contentful Paint (FCP) and the Largest Contentful Paint (LCP).
On the other hand, the practice of font swapping is well-known for causing unexpected layout shifts, which are directly related to the Cumulative Layout Shift (CLS) metric.
Now, let’s go through the font loading best practices to keep your CWV metrics in check.
Cumulative Layout Shift measures the significance of unexpected layout shifts on a page. Unexpected layout shifts occur when content on the page moves around without user input or prior notification:
Two things can cause layout shifts in the process of fetching and rendering:
To attack these issues, you can implement some of the following best practices:
1) Combine link rel=preload and font-display: optional
The option to combine link rel=preload with font-display: optional has been available since Chrome 83, and it’s said to be a surefire way to avoid layout shifts.
As previously mentioned, when a font uses the font-display: optional value, it has 100ms to be downloaded and executed before the browser goes back to the fallback.
In case that the font is downloaded before the 100ms mark, the custom font is used on the page.
That leads to the browser re-rendering the page, which in turn causes a slight flicker of invisible text.
In Chrome 83, the first render cycle is removed for optional fonts that use the link rel=preload and it’s replaced with a block period (100ms) until the custom font has loaded or the period completes.
Now the font loading process looks like this when the font is preloaded and downloaded after the 100ms block period:
And like this when the font is preloaded and downloaded before the 100ms mark:
This technique pretty much solves the problem with unexpected layout shifts and flashing of unstyled texts.
2) Use size-adjust
Another problem with font swapping is that sometimes when the web font loads, it shifts the entire page around since it presents at a slightly different box height size.
Putting the size-adjust descriptor in the font-face rule will lead to minimal visual change and almost a seamless swap.
Check out Google’s guide on CSS size-adjust for @font-face to learn how you can implement it.
3) Making your fallback font match your web font
To reduce the swap effect, you can try to make the fallback and the web font look as similar as possible. Of course, you cannot avoid shifts altogether, but you can try to make them less impactful so that they won’t harm the user experience as much.
The Font Style Matcher app by Monica Dinculescu is a well-known tool for font matching.
It allows you to overlay the same text in two different fonts to see how different they are. After that, you can adjust their font settings to get them more closely aligned.
Unfortunately, like any other font loading optimization technique, it has its risks and hurdles.
The issue with the font style matching is that you can’t have these CSS styles apply only to the fallback fonts, so you need to use JavaScript and the FontFace.load API to apply these style differences when the web font loads.
In his lecture from 2018, Zach Leatherman explains this technique in further detail:
When it comes to font loading and improving the Largest Contentful Paint metric, the techniques we will go through are a bit more general.
LCP measures the time it takes for the largest above the fold content element to load (e.g., text, image). Everything below 2.5s is considered good LCP time:
Another metric that is not part of the CWV but still could be affected by loading heavy font files is First Contentful Paint (FCP).
FCP measures the time for the browser to visualize the first piece of DOM content (e.g., text block, image, SVG, non-blank canvas element) on a page.
Both metrics measure how fast your website paints elements of the above the fold content, which play a massive role in visitors’ first impressions.
If they stare at a blank screen for quite a while (FCP), that would not be a great user experience. The same goes for waiting too long for your largest/hero element (LCP) to render.
Optimizing your web fonts is one way to improve your site’s perceived performance and guarantee a better user experience.
Here are a couple of techniques that you might want to give a go:
1) Compress your fonts
To understand how font compression works, you need to know the anatomy of a web font.
A web font is a collection of glyphs, and each glyph is a vector shape that describes a letter or symbol. Although individual glyphs are different, they contain a lot of similar information that can be compressed.
To be able to apply the correct compression, you need to know the different font formats first:
Then, you can apply GZIP compression (if needed) by using an online tool or making some server configurations.
2) Inline fonts
In general, fonts are stored in an external CSS stylesheet. To use the stylesheet, a link is placed in the head tag of the HTML markup like this:
However, running external CSS files is more time-consuming as the browser first needs to locate and then download the file.
To speed up the font loading process, you can inline font declarations and other critical styling in the head tag of the main document rather than keeping them in an external stylesheet:
This will allow the browser to locate and start rendering the font faster as it doesn’t need to wait for the external stylesheet to download.
3) Make sure your fonts are downloaded quickly
It seems like a never ending debate when it comes to choosing between self-hosting fonts or relying on third parties.
While web fonts are a great self-hosted option as they are static resources that aren’t regularly updated, relying on third-party resources is not a bad option either.
In fact, the Web Almanac found that some sites that use third-party fonts had a faster render than sites that used first-party fonts:
Source: HTTP Archive
At the end of the day, the most important thing is - how quickly are your fonts being downloaded and rendered? And most of the time, the answers doesn’t depend on your hosting approach, but rather on whether you have these three things in place or not:
So instead of wasting time on questions like “Should I self-host my web fonts or not?”, make sure that you have the more important elements set up.
4) Preconnect to third-party resources
Another technique that will allow your fonts to be loaded quickly is using link rel=preconnect.
Use the link rel=preconnect resource hint to establish an early connection(s) with the third-party origin.
Adding link rel=preconnect informs the browser of your page’s intent to establish a connection to another domain and that you'd like the process to start as soon as possible. Resources will load more quickly because the setup process has already been completed by the time the browser requests them.
Resource hints should be placed in the head tag of the document.
5) Subset your fonts
Getting back to the fact that a web font is a collection of glyphs, one thing you need to know is that some fonts can include thousands of glyphs. And the truth is - your site doesn’t use all of them.
But…
The browser still needs to download them, which can lead to slower loading time!
Enter font subsetting.
Font subsetting means trimming your fonts down to only the glyphs you use on your site. Subsetting can yield massive amounts of size savings and lead to loading fonts faster and better overall performance.
One way to do it is to use fontTools which allows you to subset fonts by arbitrary character lists. But to do it successfully and efficiently, you need to build a solid process to get every character you use on your web pages, which might not be the easiest task to do.
Improving web performance can be a lot of work and headaches. That’s why using tools and services can be really helpful.
For instance, NitroPack includes all kinds of different features that will save you a lot of time when optimizing fonts:
Also, NitroPack allows you to configure default font rendering behavior.
Go to "Fonts" settings and enable "Override font rendering behavior":
Furthermore, in the “CSS" settings you will also find the option to optimize your CSS delivery:
The latest addition to our portfolio is Font Subsetting.
When enabled, NitroPack creates a subset version of the original font file by removing all unused glyphs. Depending on the number of glyphs removed (in many cases, it is hundreds or even thousands of them), it can reduce your fonts' size drastically, making them much faster to load by the browser. As a result:
We’re also constantly testing different font configurations to see their impact on Core Web Vitals and eventually find the best solution. In fact, this process of non-stop experimentation, along with the help of our Speed Insiders, is what allows us to offer optimal CWV results to our clients:
And if you decide to become part of the NitroPack community, you should know that it takes no more than 5 minutes to set it up, and you can try our service with the free plan (no CC required).
Niko has 5+ years of experience turning those “it’s too technical for me” topics into “I can’t believe I get it” content pieces. He specializes in dissecting nuanced topics like Core Web Vitals, web performance metrics, and site speed optimization techniques. When he’s taking a breather from researching his next content piece, you’ll find him deep into the latest performance news.