blog

My font loading strategy

For a long time my font-loading strategy involved using Web Font Loader to avoid FOIT.

I would add following snippet in the document <head>:

<script>
(function(d) {
if (sessionStorage.webfont) {
d.documentElement.classList.add('wf-active');
return;
}

window.WebFontConfig = {
custom: { families: [ 'my-font:n4' ] },
active: function() { sessionStorage.webfont = true; }
};

const wf = d.createElement('script');
const ref = d.scripts[0];
wf.async = true;
wf.src = 'https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
ref.parentNode.insertBefore(wf, ref);
})(document);
</script>

And my CSS looked something like this:

@font-face {
font-family: 'my-font';
src:
url('fonts/my-font.woff2') format('woff2'),
url('fonts/my-font.woff') format('woff'),
url('fonts/my-font.ttf') format('truetype');
font-weight: 400;
font-style: normal;
}

body {
font-family: sans-serif;
}

.wf-active body {
font-family: 'my-font', sans-serif;
}

font-display

When font-display property was introduced to CSS, I quickly added it to my existing setup.

@font-face {
font-family: 'my-font';
src:
url('fonts/my-font.woff2') format('woff2'),
url('fonts/my-font.woff') format('woff'),
url('fonts/my-font.ttf') format('truetype');
font-weight: 400;
font-style: normal;
+ font-display: swap;
}
    if (sessionStorage.webfont
+ || "fontDisplay" in document.documentElement.style) {
d.documentElement.classList.add('wf-active');
return;
}

And now, when font-display is widely supported my font loading strategy looks like this:

@font-face {
font-family: 'my-font';
src:
url('fonts/my-font.woff2') format('woff2'),
url('fonts/my-font.woff') format('woff'),
url('fonts/my-font.ttf') format('truetype');
font-weight: 400;
font-style: normal;
font-display: swap;
}

body {
font-family: 'my-font', sans-serif;
}

I find this works great for me most of the time. There can be an issue with loading multiple fonts where each font causes a new repaint. In that case, it’s advisable to fall back onto a JS-based approach but I don’t do it by default.

Cloud-hosted fonts

Today, Google Fonts support font-display so that’s great. On top of it, I like to de-prioritize fonts from critical styles by asyncronosly loading CSS file with @font-face definitions:

<head>
<link rel='preconnect' href='https://fonts.gstatic.com' crossorigin>
<link rel="preload" href="https://fonts.googleapis.com/css?family=Fira+Mono&display=swap" as="style" />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Fira+Mono&display=swap"
media="print"
onload="this.media='all'">

</head>

That’s how I load monospace font used in code examples on this blog. I use same approach at Hugo where a single typeface (that we self-host) is used across multiple products.