loading...

What's the most efficient way to load custom fonts on the web

ben profile image Ben Halpern ・1 min read

DEV only uses system fonts to prioritize performance over other concerns... But I know there are new techniques and APIs for font loading consistently rolling out.

In 2020 and beyond, what's the outlook for font loading?

Discussion

markdown guide
 

I don't see any mention yet of Harry Roberts' excellent post on speeding up Google Fonts: csswizardry.com/2020/05/the-fastes...

This is the TLDR;

<!--
  - 1. Preemptively warm up the fonts’ origin.
  -
  - 2. Initiate a high-priority, asynchronous fetch for the CSS file. Works in
  -    most modern browsers.
  -
  - 3. Initiate a low-priority, asynchronous fetch that gets applied to the page
  -    only after it’s arrived. Works in all browsers with JavaScript enabled.
  -
  - 4. In the unlikely event that a visitor has intentionally disabled
  -    JavaScript, fall back to the original method. The good news is that,
  -    although this is a render-blocking request, it can still make use of the
  -    preconnect which makes it marginally faster than the default.
  -->

<!-- [1] -->
<link rel="preconnect"
      href="https://fonts.gstatic.com"
      crossorigin />

<!-- [2] -->
<link rel="preload"
      as="style"
      href="$CSS&display=swap" />

<!-- [3] -->
<link rel="stylesheet"
      href="$CSS&display=swap"
      media="print" onload="this.media='all'" />

<!-- [4] -->
<noscript>
  <link rel="stylesheet"
        href="$CSS&display=swap" />
</noscript>```



Half of this is applicable to self-hosted fonts, too.
 

It's a great article. I've been using this too.

 

unicode-range and variable fonts are probably the fastest ways to do it!

I have this file on my personal site, which loads the Recursive font in two sections - the first is a tiny subset needed for English (the language I primarily write in). There is a great explanation of unicode-range here.

@font-face {
  font-family: 'Recursive';
  src: url('/fonts/recursive-0020_007F.woff2') format('woff2');
  unicode-range: U+0020-007F; /* The bare minimum for the English Language */
}

@font-face {
  font-family: 'Recursive';
  src: url('/fonts/recursive.woff2') format('woff2');
  unicode-range: U+00A0-00FF, U+0100-017F; /* additional glyphs */
}

The other big win is using variable fonts - they limit the amount of code needed to deliver a wide range of fonts by encoding how the font changes at different widths, slants, and styles directly in the font file. Recursive is what I use, but there are a good number of other variable fonts out there!

recursive.design/
v-fonts.com/

 

Thank you this is a really good reply! I did not know about unicode-range.

 

Yeah, it's a great tool, but I don't see a ton of people working with it, but it's sooo good.

 

Self hosted fonts are the best way to go, but google fonts is still pretty fast. Be sure to keep your assets on a CDN.

Formats used to be a mess. Nowadays, I usually just keep it at woff and woff2. That covers all modern browsers and IE11. Everything else can safely fall back to a system font.

You can strip out characters you don't need. If you write exclusively in english, let go of all the pesky umlauts, northern ligatures and cyrillic character sets. That goes for iconfonts as well, strip out any icons you don't need.

Font display is a really nice tool to prevent font flashes (as in, your font didn't download yet). You can set a fallback font until the webfont is loaded, or just leave it at the fallback, if the webfont takes a long time to download. Chances are, the user has already begun reading at that point.

As with any asset, you can preload it with

<link rel="preload" href="/path/to/font.woff2" as="font" crossorigin>

. It moves the font further up the waterfall diagram and prioritizes it higher.

And last but not least, if you use lots of font styles of the same family, variable fonts are worth checking out. They let you use one (quite large) font file and style its properties (like thickness, slant, and custom ones) in css dynamically.

 

One of the most underrated tools for font loading is the unicode-range property for @font-face loading. It can really help decrease bundle sizes and loading times, especially when loading more than 2 fonts and the content is in one primary language.

 

There are a lot of good responses here. I'm going to have to look into some of these.

Also, I agree that system fonts perform best. But when it comes to branding, I think it'll be hard to convince someone who wants the same fonts used everywhere to do something else for web, especially if it's someone who gets hung up on the look of something before even seeing the actual content.

Of course, that's not to say the performance argument shouldn't be made. Just wanted to throw this out there.

 

If you are using a common font such as Roboto, Open Sans your navigator might be storing the font locally itself so you could use local within src.

@font-face {
  font-family: 'Roboto';
  src: local('Roboto'), local('Roboto-Regular'),
  url('/resources/fonts/roboto/woff2/roboto-regular.woff2') format('woff2'),
  url('/resources/fonts/roboto/woff/roboto-regular.woff') format('woff'),
  url('/resources/fonts/roboto/truetype/roboto-regular.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-stretch: normal;
  font-display: swap;
  unicode-range: U+000-5FF;
}
 

That's interesting. I bet we could test that out on a site my employer owns.

 

Can’t believe no one mentioned subfont.

It creates a local copy for you if you host it on google. It rewrites the font tags. It uses a graph to see what you use and prunes the fonts for just the characters needed. And probably 20 more things I didn’t think of.

I run it against a static site after generating. Not sure how to work this into our workflows.

github.com/Munter/subfont

 
 

I tend to use Google Fonts. And stick to the system fonts. But hosting the fonts on the CDN as a very good idea. I completely forgot about link rel preload. I've created and used various font preloaders for various formats. Google fonts do the trick.

As for font flashing I used a trick many years ago which was to render the font off screen before hand. This discussion is enriching.

 

Is it possible to stream fonts as opposed to load fonts? For example, HanaZono is around 20MB x2 files, and it covers most CJK characters, many of which are rare and you might not need.

Otherwise, split fonts on server-side?

 

I was using webfontloader in the previous version of my site.

GitHub logo typekit / webfontloader

Web Font Loader gives you added control when using linked fonts via @font-face.

Web Font Loader

Web Font Loader gives you added control when using linked fonts via @font-face. It provides a common interface to loading fonts regardless of the source, then adds a standard set of events you may use to control the loading experience. The Web Font Loader is able to load fonts from Google Fonts, Typekit, Fonts.com, and Fontdeck, as well as self-hosted web fonts. It is co-developed by Google and Typekit.

Build Status

Contents

Get Started

To use the Web Font Loader library, just include it in your page and tell it which fonts to load. For example, you could load fonts from Google Fonts using the Web Font Loader hosted on Google Hosted Libraries using the following code.

<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js">

I was using Gatsby under the hood, so webfontloader was wrapped in this Gatsby plugin, gatsby-plugin-web-font-loader.

 

There are different ways. But you want something blazing fast then here is a trick...

dev.to/manishfoodtechs/server-push...

110% faster next-time ...

 
 

display swap is interesting, but even after implementing, lighthouse flags it.

 

Custom CDN and preloading with HTTP. I don't like Google fonts, not because they are slow but because loading fonts we share data with third party service (similar mechanism to fb pixel).

 

Pedantic answer, don't. I'd prefer to use the system fonts to try and make the website feel more native to the platform the user is on.