DEV Community

Cover image for Preload Fonts
Daniel Bellmas
Daniel Bellmas

Posted on • Updated on

Preload Fonts

Usually, fonts are either downloaded from a third-party source, such as Google Fonts, or from a file that is stored in the build folder.

After running the build we get a static folder that houses 2 folders: js, css.
If we downloaded some font files they will be inside a third folder: media.

We can manually download them, or download a npm package, like @fontsource, that inside it has the files.

The browser will then load those at its own pace, but that will probably cause a UI flicker of the default browser fonts and then the desired fonts.

For a better UI feel, we have to tell the browser to preload them.

In order to achieve that we need to add a link tag that preloads the href it's given:

<link
rel="preload"
href="https://fonts.gstatic.com/s/poppins/v20/pxiEyp8kv8JHgFVrJJfecnFHGPc.woff2"
as="font"
crossOrigin="anonymous"
/>
Enter fullscreen mode Exit fullscreen mode

But how do I know what to put inside the href?

For that, we need to open the network tab in the dev tools, see what the browser loads, and copy it :)

Font url in the network tab in dev tools

To locate the font request, choose the Font filter at the top.

If we are using React we can add this link tag to the index.html (just like in Vanilla JS) or inside our App.tsx, but to access the head tag from App.tsx we'll need to use the help of the react-helmet-async library.
All it does is insert its children to the head tag.
And of course, instead of "dirting" our App.tsx with more code, we can wrap it in a separate component - <PreloadFonts />

This nav bar, for example, will look like this for a split second (the gif is slowed down for a better look at the change).

UI flicker when not preloading

But after preloading the font we get no flicker:

After preloading

The same process applies to the fonts that come from a library or font files that we downloaded, the only difference is that the href will be relative, like so:

<link
rel="preload"
href="/static/media/libre-franklin-latin-400-normal.woff2"
as="font"
type="font/woff2"
crossOrigin="anonymous"
/>
Enter fullscreen mode Exit fullscreen mode

Now my question is why not all fonts are preloaded automatically if there is an evident UI flicker?!

Funny meme from friend where Joe says why god?!

Top comments (6)

Collapse
 
fruntend profile image
fruntend

Сongratulations 🥳! Your article hit the top posts for the week - dev.to/fruntend/top-10-posts-for-f...
Keep it up 👍

Collapse
 
madza profile image
Madza

This is always a great practice 👍✨

Collapse
 
yuridevat profile image
Julia 👩🏻‍💻 GDE

Thanks for the article!

This is indeed a good question, but thanks to your article we at least have a good way to prevent flicker to happen.

Collapse
 
chewbecca profile image
Becca Owens

Thanks, I just implemented this in my design system!

Collapse
 
itsmnthn profile image
Manthankumar Satani

This is great practice but it sometimes takes more time to load fonts if the page is using multiple or multiple weight of the fonts

Collapse
 
itsmnthn profile image
Manthankumar Satani

I solve it with

style.css

body:not([data-font*='inter']) {
  /* Font setting of sans-serif with inter for minimal FOUC Used https://meowni.ca/font-style-matcher/ */
  font-family: sans-serif;
  font-size: 16px;
  line-height: 1.5rem;
  visibility: visible;
  letter-spacing: 0.45px;
  word-spacing: 0.3px;
}

body[data-font*='inter'] {
  font-family: Inter, sans-serif;
  font-size: 16px;
  line-height: 1.5rem;
  visibility: visible;
  letter-spacing: 0;
  word-spacing: 0;
}
Enter fullscreen mode Exit fullscreen mode

index.html

<link rel="stylesheet" media="all" href="/css/font.css" onload="this.media='all'; window.document.body.setAttribute('data-font', 'inter');">
Enter fullscreen mode Exit fullscreen mode