Fighting FOUT

Web fonts are great when they work properly.

Gav McKenzie
Author
Gav McKenzie
Published
Jul 25, 2017
Topics
How-to, Industry, Engineering

Working with the web, you’ve always got the chance that your users are on a dodgy internet connection. Or maybe they have JavaScript switched off (yes, some people still do!). Or maybe something broke in your code.

Web fonts, although they can make your site look awesome, are a prime candidate for a failure point between your users and your content.

Let’s look at some of the common loading techniques, where they fail, and how to prevent failures.

Loading with CSS

There are two main options with CSS font loading. You can put the @font-face declaration directly in your CSS file or add a separate >link< tag.

Render blocking

Both these options prevent the page from rendering until your awesome web font has finished downloading. Users won’t be able to see anything until they have downloaded all the font files, which can end up pretty large!

Render blocking font loading

Slow connections or connections that drop out can cause your page content to never get rendered, leaving frustrated users.

So how do we prevent render blocking?

Loading with JavaScript

The two main powerhouses of fonts on the web have team up to provide a great JavaScript based solution to our problems: Web Font Loader

The Web Font Loader allows you to asynchronously load your fonts onto the page, letting the rest of your content finish rendering whilst the fonts are downloading.

WebFontConfig = {
google: {
families: ['Nunito']
}
};
// Async the webfont loader
(function(d) {
var wf = d.createElement('script'), s = d.scripts[0];
wf.src = '[https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js'](https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js');
wf.async = true;
s.parentNode.insertBefore(wf, s);
})(document);

Whilst this is awesome, it can lead to the “Flash Of Unstyled Text” as users are shown the fallback font before the real fonts have loaded.

Hidden text loading in

Hiding text before loading

In order to prevent users seeing FOUT, we’ll hide the unstyled text in some common elements before the font has loaded.

Web Font Loader provides a couple of useful classes we can utilise for show the text again once the fonts are ready. .wf-active tells use the fonts have loaded correctly, whilst .wf-inactive lets us know the fonts have failed.

In either case, we now want to show the text so users can consume our content. We’ll also add a fade using opacity to make the transition smoother.

Transition slowed down due to terrible gif framerate

Transition slowed down due to terrible gif framerate

h1,
h2,
h3,
h4,
h5,
p,
a {
opacity: 0;
transition: opacity .2s ease-in-out;
}
.wf-active,
.wf-inactive {
h1,
h2,
h3,
h4,
h5,
p,
a {
opacity: 1;
}
}

No JavaScript

What happens if the user has JavaScript switched off? We don’t want to prevent users from seeing our content.

A few years ago, the technique was to use Modernizr, which would add a class of .js to your <html> tag to show JavaScript was available. We would wrap the CSS with a .js class to prevent the text being hidden when no JS was available to load the fonts.

.js {
h1,
h2,
h3,
h4,
h5,
p,
a {
opacity: 0;
transition: opacity .2s ease-in-out;
}
.wf-active,
.wf-inactive {
h1,
h2,
h3,
h4,
h5,
p,
a {
opacity: 1;
}
}

However, waiting for the external lib of modernizr to load (or any external file), could end up with the page rendering, then the text hiding, then showing again. Disaster!

The solution is to add a tiny piece of inline JS at the top of the page to determine that JavaScript is available.

<script>
var html = document.querySelector("html");
html.classList.add("js");
</script>

Slow JavaScript

All this asynchronous clever loading is great, but what happens when the JavaScript fails?

Currently, the fonts will only show if the html has a class of .wf-active or .wf-inactive. If we just have a slow connection and the web font loader finishes loading successfully, but the fonts are too slow, the class of .wf-inactive will be applied by the timeout functionality in the Web Font Loader.

However, this is the internet and we cannot rely on the Web Font Loader loading successfully.

We’ll add our own simple timeout as part of the inline JavaScript at the top of the page that told us we have js.

<script>
var html = document.querySelector("html");
html.classList.add("js");
setTimeout(function() {
html.classList.add("wf-slow");
}, 3000);
</script>

Now we have a class of .wf-slow available when the external JS either fails to load or is too slow.

.js {
h1,
h2,
h3,
h4,
h5,
p,
a {
opacity: 0;
transition: opacity .2s ease-in-out;
}
.wf-active,
.wf-inactive,
.wf-slow {
h1,
h2,
h3,
h4,
h5,
p,
a {
opacity: 1;
}
}

Now, all users regardless of JavaScript, slow connections or failed connections will get to the content in a timely manner, presented in the best way possible for the current abilities of their browser.

tl;dr

Use this technique to load your fonts for minimum FOUT and maximum content delivery.