Web Fonts in 2021

Typography accounts for 95% of web design. Your font choice can be critical for branding, readability, and performance.

Over time, recommendations for using web fonts have changed as browsers adopted new standards. Now in 2021, I wanted to learn the best practices for using web fonts on high-performance sites.

System Fonts

The fastest way to use a web font is none. Browsers include a set of web-safe fonts (e.g. Arial, Georgia, Times New Roman) you can use by default.

Using web-safe fonts or the system font stack will be the fastest option.

font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial,
  sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';

Why Use Web Fonts?

If system fonts are the fastest option, why do web fonts exist? Branding, improved design, and cross browser and device consistency. 82% of web pages for desktop use web fonts.

Let's cover five different areas for high-performance web fonts and conclude with a 2021 recommendation.

  • Self Hosting
  • Preloading
  • Font Display
  • Variable Fonts
  • Subsetting

Self Hosting

Google Fonts is responsible for 70% of all web font usage. With over 1000 fonts, they provide easy access to quality fonts, multiple formats, and performant defaults (pre-connecting and swapping).

However, Google Fonts is no longer necessary. Since 2018, Google has advised self-hosting for optimal performance through preloading.

There aren't any caching advantages anymore, either. Let's say you're using the font "Roboto", which is a popular font on Google Fonts. Chances are you've visited another site using "Roboto" and cached the font.

Since October 2020, Chrome no longer allows a shared cache across sites. Safari has worked this way since 2013. "Roboto" will be re-downloaded for every site, regardless of it being cached.

When self-hosting, ensure you cache your font with the Cache-Control HTTP header. immutable tells the browser the file will never change. When a request is made within the max-age (1 year), it avoids the roundtrip to ensure it's the latest content.

Cache-Control: public, immutable, max-age=31536000

If you need Google Fonts, use these optimizations. With the latest changes in the v2 API, you can tailor fonts to specific users and platforms (including variable fonts).

Preloading

The browser assigns loading priorities to different types of resources. By default, CSS will be loaded before scripts and images. You can influence the importance of resources by preloading critical assets.

Fonts are discovered late by the browser by default. By preloading, we fetch the font file as soon as possible. Then, the browser caches the font making it available immediately.

Preloading can improve performance metrics like Time to Interactive and First Contentful Paint. For example, Shopify saw a 50% (1.2 second) improvement in First Contentful Paint, removing their Flash of Invisible Text (FOIT).

As of 2020, 75% of web fonts use WOFF2. You likely only need this. For example:

<link
	rel="preload"
	href="/fonts/inter-var-latin.woff2"
	as="font"
	type="font/woff2"
	crossOrigin="anonymous"
/>

Support: All modern browsers except Firefox.

Font Display

font-display allows you to modify the rendering behavior of web fonts with values such as auto, swap, block, fallback and optional. When loading web fonts, we want to prevent layout shift. This occurs in two ways:

  • Flash of Unstyled Text (FOUT) — The fallback font is swapped with a new font (e.g. swap).
  • Flash of Invisible Text (FOIT) — Invisible text is shown on the page until a new font is rendered (e.g. block).

Browsers currently have a default strategy similar to block. The only option that eliminates layout shift is optional. Combined with the other performance optimizations in this article, optional is your best choice.

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-display: optional;
  src: url(/fonts/inter-var-latin.woff2) format('woff2');
}

Support: All modern browsers

Variable Fonts

Variable fonts allow us to combine multiple styles and weights (e.g. bold, italic) into a single font file.

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900; // Range of weights supported
  font-display: optional;
  src: url(/fonts/inter-var-latin.woff2) format('woff2');
}

You can try out different variable font options here.

Support: All modern browsers. Even Google Fonts v2 API has support for variable fonts.

Subsettings

Font files contain multiple languages and glyphs, which increase the file size. Subsetting is the removal of characters you don’t need.

For example, we might use the Inter variable font and subset to latin languages.

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900; // Range of weights supported
  font-display: optional;
  src: url(/fonts/inter-var-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}

Conclusion

  1. Use a variable font
  2. Preload your font file
  3. Self-host instead of Google Fonts
  4. Use font-display: optional to prevent layout shift

Here's an example of a site implementing all these recommendations.

Future

If you need to use font-display: swap, future support for Font Metrics Override will reduce layout shift when swapping.

@font-face {
  font-family: ...;
  src: ...;
  ascent-override: 80%;
  descent-override: 20%;
  line-gap-override: 0%;
  ...;
}