Story heading

10 ways to speed up web font loading

December 19, 2023

Fonts are popular tools on the web nowadays. Most modern websites use custom fonts, usually from Google Fonts, because they add a custom touch to the interface and allow for more optionality. However, there are many performance implications with fonts on the web. Fonts are often hundreds of kilobytes and are hosted on another domain, slowing down the website. Luckily, you can solve these problems. Here are ten tips to improve font loading performance on a website.

How to make web fonts load faster

1. Self host your fonts

When you go on a website and look at the HTML, you often see something like this:

<link rel="preconnect" href="" />
<link rel="preconnect" href="" crossorigin />

That means the website is using Google Fonts to load fonts. Google Fonts is excellent for prototyping, as it is straightforward. Sadly, it is terrible for performance. Performance is bad because Google Fonts has a complicated string of requests to get a font, which adds significant latency.

Google font loading diagram

As you can see, Google Fonts loads fonts in a pretty convoluted way. However, you can reduce the number of requests you need by self-hosting the font and putting the @font-face declaration inside your CSS bundle instead of an external stylesheet. A tool like Google Webfonts Helper can be helpful for this.

You can also use tools built for specific frameworks like next/font for Next.js. These tools automatically download the font file and include it in the build process, allowing you to take advantage of the better performance without having to manage the font files yourself.

2. Use modern web font formats

Just like images, web font formats have evolved over time to become more compact. With images, modern web formats like AVIF and WebP replaced less compressed formats like PNG and JPEG. Similarly, WOFF and WOFF2 are web font formats with superior compression to TrueType and OpenType (TTF and OTF). Additionally, modern web font formats are almost universally supported:

WOFF Support from CanIUse (98.36% of users support it)

Because of the almost universal browser support, the best format strategy to use is WOFF2 with a WOFF fallback, although you could even use WOFF2 alone, as ~97% of users support it.

3. Subset your fonts

Font subsetting means trimming your fonts down to only the characters you need. Subsetting can yield massive amounts of size savings without drawbacks as long as you are not using the characters you remove. The simplest way to do this is subsetting to remove languages that you do not use. For example, take Inter, one of the most popular fonts. If you include all alphabets, which include Latin, Cyrillic, Vietnamese, and Greek, the size of the WOFF2 font is 95kb. However, chances are you are not using all of those alphabets. Removing all characters outside of the English language reduces Inter’s size to just 16kb!

There are many ways to subset fonts, including Google Fonts (and by extension, Google Webfonts Helper), Everything Fonts, and fontTools.

The size reduction benefits performance, but you can do even better if you are willing to take on more complexity. Instead of subsetting by wide character ranges, you can subset to include only the characters you use. Tools like fontTools allow you to subset fonts by arbitrary character lists. The problem with this approach is that you need a complicated build process to get every character you use. Or, of course, you can manually add each character, but that is a lot of work 🙁. Ultimately, you can get most of the benefits with much less work by just removing languages/alphabets you do not need.

4. Use font-display

By default, text will not appear in many browsers until the correct font is loading. That behavior is called Flash of Invisible Text, or FOIT. Some other browsers display text using the fallback font while it is loading, ensuring text is not invisible, but that can cause a layout shift.

Luckily, you can customize font loading through the font-display option in your @font-face declaration. The two recommended values for font-display are swap and optional. swap uses a fallback font and then switches to the custom font once it is loaded, and optional blocks page load for a maximum of 100ms to let the font load, and if it does not, it uses a fallback font.

@font-face {
	font-family: "Example";
	font-style: normal;
	font-weight: 400;
	src: local("Example"), local("Example"),
		url( format("woff2");
	font-display: swap;

font-display: optional is the best for when you don’t need the font to be loaded because it prevents any layout shift and ensures the text is not invisible. However, font-display: swap is best when you need the font to load because it swaps in the font even if it takes more than 100ms. font-display: swap can cause issues with layout shifts like mentioned above, but the next tip can help you solve that.

5. Match your fallback font with your custom font

Fonts are usually spaced and sized differently. For example, Merriweather is larger than Georgia, even if the CSS font size is the same. These inconsistencies can cause a layout shift if you use font-display: swap and make fonts less consistent if you use font-display: optional.

Luckily, you can configure your fallback font to look much more like the web font you are using. Matching both fonts can be done by customizing spacing and font size through CSS properties in the @font-face to remove inconsistencies. A helpful tool for this is Font Style Matcher, which allows you to look at two different fonts, configure various spacing properties, and see a demo of the layout shift.

6. Use a CDN

CDNs are great for speeding up static content delivery. They deliver content closer to your users and often offer other ways of speeding up delivery. Hosting your fonts on a CDN with all your other static assets is a good idea. Using a CDN also reduces server costs, as CDNs are generally cheaper than serving the request from your source server.

Most major cloud providers, like AWS, Azure, and GCP, all have CDN services. You can also use a CDN like Cloudflare if you can’t use a CDN integrated with your other hosting tools.

7. Preload your fonts

Preloading is often a good idea for fonts, as it lets the browser know it needs to download a resource sooner and increases that resource’s priority. Instead of waiting to load and parse the CSS containing the font declaration, the browser can start downloading the font immediately. However, you do not always want to preload your fonts because it might unnecessarily load a font.

Normally, the browser automatically detects whether the website uses a font on the page before downloading it, even if the @font-face is present. If the browser finds no text with that font, it will not download it. However, the browser cannot do this with preloaded fonts because the browser must start downloading the font immediately.

Now, you might know that you always use the fonts you include with @font-face, and therefore there is no chance of an unnecessary font load. Unfortunately, there is one other potential problem. If your font is not immediately needed, the drawbacks of deprioritizing the loading of other resources might outweigh the benefits. However, if these two potential issues aren’t problems for you, preloading can greatly speed up your fonts.

8. Use local()

Depending on the font, users can often have the font you are using locally installed on their machine. If they do, you can use the font locally to prevent any performance degradation from downloading a custom font through a local() statement in your @font-face rule.

@font-face {
	font-family: "Awesome Font";
	font-style: normal;
	font-weight: 400;
	src: local("Awesome Font"),
		url("") format("woff2");

This @font-face checks if the user has the font locally, and if they do not, downloads it remotely. That means that users with the font get a free performance boost while adding little complexity to the code and no disadvantage to users who do not have the font locally. If you want to focus on fonts that computers usually have, you can check out Windows 11’s font list and macOS Sonoma’s font list.

Unfortunately, it is essential to note modern browsers limit this capability to prevent fingerprinting. Webkit only allows local to load fonts installed by default in the operating system, meaning user-installed fonts will not appear.

9. Implement Caching

Caching is very important, especially if you have lots of repeat visitors. Caching allows the font to load from the disk after the first time it is downloaded. You can implement caching through the Cache-Control header. If you use a CDN like Cloudflare, it is simple to do from the dashboard. Otherwise, you can do it by simply sending the header with your font responses.

10. Don’t use custom fonts

I bet you didn’t see that one coming 😉. While all of these techniques are great, ultimately, the best performing web font is no web font. System fonts are great for unbranded text like body text. Even beyond the performance advantages, properly implemented system fonts look far more well integrated because they use the same font as the parent operating system. The feeling of integration has led companies like GitHub to use a standard system font stack.

You can implement system UI fonts through a system font stack like this one, which this blog uses:

font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui,
	helvetica neue, helvetica, Ubuntu, roboto, noto, arial, sans-serif;

The font stack above contains a variety of fonts, first listing fonts for popular operating systems, then listing web safe fonts. You could also just use one font family, system-ui. However, system-ui is known to have some internationalization issues when users have default languages that are not the webpage’s language.


That is all! I hope you enjoyed learning how to optimize your web fonts, and I hope this has helped you optimize fonts on your websites. If you want to speed up other areas of your website, like images or JavaScript, check out these articles:

If you enjoyed reading this, sign up for the mailing list below and subscribe to RSS. Thanks for reading!


Sign up for email updates

Get interesting posts about web development and more programming straight in your inbox!