How to load web fonts for the best page load performance

Custom web fonts are used all across the internet, but many websites could improve how they load them. Loading web fonts improperly can certainly cause problems for page loading performance, making a website much slower, which in turn will have an impact on website sustainability.

Loading web fonts efficiently only takes a few steps:

Use the correct font format

There are many font formats that can be used on the web, but only two of those formats are really needed if you don’t have to support legacy Internet Explorer versions. These formats are; woff and woff2. The benefit of using only these two formats is that they are compressed by default with gzip (meaning they can be very small in file size), they are optimised for the web, and are fully supported by IE 9+ and all other modern browsers.

Preloading web fonts

The word preloading feels slightly misleading to us. Essentially we want to tell the browser to load the font files as quickly as possible using the appropriate rel="" tag and attributes.

<link rel="preload" as="font" href="/fonts/custom-font.woff2" type="font/woff2" crossorigin="anonymous">
<link rel="preload" as="font" href="/fonts/custom-font.woff" type="font/woff2" crossorigin="anonymous">

A quick note: The use of crossorigin here is important; without this attribute, the preloaded font is actually ignored by the browser, so a new fetch of the font file will take place, undoing our lovely work. Browsers expect to fetch fonts anonymously. This is why our request to preload the font file needs to be made anonymous.

In the examples above, the rel="preload" as="font" attributes will ask the browser to start downloading the font as soon as it can. The code also tells the browser that this file is a font, so it can appropriately prioritise it in its loading queue. Browsers that support preload and prefetch hints will begin downloading the font as soon as they have seen the hint in the HTML file. This means they no longer need to wait for the CSS that loads the font.

What if you have multiple webfonts, but one is not needed for the initial paint above the fold?

Say you need to load two web fonts on your website, but you only use one of those fonts in the header area that sits ‘above the fold’. Instead of using rel="preload" on the second web font, you can use rel="prefetch". This attribute tells the browser to prepare the download of the resources, but gives it a lower priority in the loading queue.

Preload usage with Content Delivery Networks

If you’re using a CDN to host your assets across a network, like Google Fonts, you need to ensure that the font file(s) you’re preloading match the one(s) used in the CSS. This can get tricky, due to fonts on these platforms potentially having updates. If for example you’re preloading an old version of the font whilst using the CSS for a newer version, you might actually end up downloading two versions of the same font on the frontend, therefore wasting the users’ bandwidth – and again, undoing our lovely work.

Correct font-face declaration

Declaring a font-face family is a very simple bit of code, but the importance of declaring things in the right order cannot be understated. This example shows the correct order in which to load font-face files for the best page load performance.

@font-face {
  font-family: 'Custom Font';
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+000-5FF; /* Downloads only latin glyphs */
  src: local('Custom Font'),
       url('/fonts/custom-font.woff2') format('woff2'),
       url('/fonts/custom-font.woff') format('woff');

As previously mentioned, the code only uses the optimised web fonts (woff and woff2). The code tells the browser to load only the required latin glyphs, however this property doesn’t prevent the browser from downloading the entire font. You’ll notice a couple of lines not yet mentioned, the use of the local() function and the font declaration order.

The local() function allows the use of a users local copy of the font if it is present on their device. For example, the web font Roboto from Google Fonts is already installed on Android devices. If viewing a website using Roboto that included this set up, the device would use the installed local version of the font instead of downloading a different version.

The font declaration order is also important because the browser will start fetching the font(s) by following that order in sequence. If it supports the woff2 format it will download the font. If it doesn’t recognise the format it will proceed to the next one, try loading that one, and so on.

If you really want to use eot and ttf fonts make sure to add them at the end of the src declaration, after the woff files.

Avoid invisible text or FOIT during font loading

Web fonts can be quite large files that can take a while to load, even when compressed and gzipped. Some browsers hide text until the font being applied to it loads. Hence the term, “flash of invisible text”. You can avoid invisible text by using a system font initially, then, once your web font is loaded, replace it.

In the previous @font-face example we included the font-display declaration. The swap value is there to tell the browser that text using this web font should be displayed immediately using a system font. Once the custom web font is ready, the system font is ‘swapped’ out.

Not all browsers have support for font-display. Though most do. There is no need to worry if a browser does not support it. If there is no support, the browser continues to follow its default behaviour for loading fonts.

Browser default behaviours if a font is not ready

Chrome and Firefox will hide text for up to 3 seconds. If text is still not ready, it will use a system font until the custom font is ready.

Safari hides text until the custom font is ready.

Edge uses a system font until the custom font is ready, then swaps out fonts.

Conclusion; why you should implement this web font loading approach

Considering that such a basic code change can optimise and improve the UX of your website, we think it is a no-brainer to load fonts in this way.

Remember, not everyone is on super-fast broadband. Many rely on slower internet speeds across the globe. Therefore, we must do what we can to improve the performance of websites for those users. In doing so, we not only improve the UX for those users, we improve it for all users.

That’s not all, in following this approach you are loading less font resources, saving data. For a website with a lot of page views, this data saving could be rather substantial.

If anything, we think that such small improvements, especially for large projects, should be mandatory for improving overall user experience.

Find this resource useful?

I want everyone to be able to benefit from articles like this.

That's why I need your help in spreading awareness. Please consider telling your fellow developers about the by sharing a Tweet.

Tweet about the