Advertisement
UX

Quick Tip: Avoid FOUT by Adding a Web Font Preloader

by

FOUT (a Flash of Unstyled Text) is what you'll often see in that brief moment before a browser has had chance to load and apply web fonts. Typekit and Google Web Fonts offer us a way around this inconvenience - here's a quick tip to explain exactly how.


Credit goes to Dan for this, after his recent article reminded me of the WebFont Loader. It's so useful I figured it was worth throwing into a quick tip.


FOUT

What an appropriate acronym (in Dutch it means error). In any case, when you use web fonts, they need to be loaded into your browser as assets (just like images and scripts) which can take a moment. In this situation your browser will look at the font stack..

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

..to determine which font should be displayed while the web font (Oswald in this example) is making its journey. Once the web font is available, there'll likely be a 'flash' as the fallback font disappears and the intended font takes its rightful place. Not ideal.


WebFont Loader

The webfontloader script was bashed together by Google and Typekit, and is made available by default with both of their services.

It adds class names to the <html> element to reflect the status of any webfonts being loaded. While loading is taking place, this is applied:

	<html class="wf-loading">

More specifically, classes are added for every font in the pipeline (Droid Serif Normal 400 for example):

	<html class="wf-droidserif-n4-loading wf-loading">

Once the process is complete, these classes are updated:

	<html class="wf-droidserif-n4-active wf-active">

Or in the event of a problem loading the assets:

	<html class="wf-droidserif-n4-inactive wf-inactive">

These classes give us great flexibility in determining what a user experiences at any given point in the web font rendering process. Let's now build an example to make things perfectly clear.


Step 1: Grab Some Fonts

Okay, I skipped a step, I'm assuming you have an html document to work with. Download the source files and you'll find a folder called "demo-starting-block". Open the index.html within it and you're good to go.

Head on over to Google Web Fonts and select a font or two for use in your project.


Boogaloo should do..

Once you've hit "Add to Collection", head down to the bottom of your screen and hit "Use" where you see a summary of your collection so far.

Whereas normally you might opt to link directly to the css file stored on Google's gargantuan servers, hit the JavaScript tab and copy the snippet you're given.

Google suggest you paste this snippet as the first item after the opening <head> tag - and with good reason. It's important this script is allowed to apply the class names (we spoke about earlier) as soon as possible in order to combat FOUT. If you pulled this JavaScript in after everything else on the page, the fallback font will have been given a chance to rear its ugly head..

Here's my snippet, safely where it belongs:

<head>

<script type="text/javascript">
  WebFontConfig = {
    google: { families: [ 'Boogaloo::latin' ] }
  };
  (function() {
    var wf = document.createElement('script');
    wf.src = ('https:' == document.location.protocol ? 'https' : 'http') +
      '://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
    wf.type = 'text/javascript';
    wf.async = 'true';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(wf, s);
  })(); </script>

Using @font-face

Let's apply our Boogaloo font to everything on the page (I'm not going for style points here). Open up css/styles.css and kick things off with:

body {
	font-family: 'Boogaloo', cursive;
}

All the actual @font-face jiggery-pokery has been dealt with server-side by Google - we just have to use the value as provided.

Okay, at this point you'll see the FOUT effect I've been banging on about so much (though admittedly *very* briefly). If you want to see it more clearly, try adding hundreds of fonts to your collection, that should slow things down..


Making Use of wf-*

There are all kinds of things you could do to the content on your web page, to specifically reflect the font loading status. Let's use a pseudo-element to inform users what's going on.

Continuing on in our styles.css, add an :after pseudo-element to our HTML whilst it has a wf-loading class, like so:

.wf-loading:after {

	/*	
	first up, we need
	to define some content
	*/
    content: "loading fonts..";
    
    /*
    let's now give it some
    dimensions, a background
    color and position
    it on the page
    */
    width: 100%;
    height: 100%;
    position: fixed;
    top: 0;
    left: 0;
    
    /*
    okay, so what do we want
    our label to actually
    look like?
    */
    color: #135040;
    font-size: 1.5em;
    font-weight: bold;
    line-height: 20em;
    text-align: center;
        
}

We've essentially covered the entire page with a huge label, the comments in the CSS should make it clear what's going on. Here's a screenshot of what you can see whilst the font is loading:

Of course, once the font has finished loading, the loading classes are removed and replaced with other statuses. The :after pseudo-element ceases to be, revealing the page with your web font applied. No FOUT!


Added Subtlety

The effect we just achieved does its job perfectly, but the label just disappears once the fonts are loaded, abruptly revealing the content beneath. We can improve on that, surely?

Frustratingly, transitions on generated content are still weakly supported so we can't rely on any tricks there. What we can do is hide all the page content, transitioning it in once the -loaded classes have been applied.

Try this. Get rid of all the styles we just made, placing this at the very top of your css file:

.wf-loading * {

	/*
	first things first, we need to hide everything,
	but bear in mind that this will only take effect
	once the loading script has taken effect.
	here we're hiding all content within
	the <html> once it has the class "wf-loading"
	*/
	opacity: 0;
}

body {
	font-family: 'Boogaloo', cursive;
}

This little nugget is going to hide (through reducing opacity to 0) every element within html.wf-loading. It's the very first rule, hiding everything before FOUT takes place.

With the content hidden, we can apply a background to our html element.

.wf-loading {
	
	/*
	here's a background image (at a meer 723bytes)
	to indicate something's happening
	*/
	background: url('../images/ajax-loader.gif') no-repeat center center;
	
	/*
	just to make sure the <html>
	element shares the same dimensions as
	the browser window when loading
	(and not the potentially elongated page)
	*/	
	height: 100%;
	overflow: hidden;
		
}

We've used a loader.gif generated by one of the many online tools available. Obviously, whatever the background you choose, it should be lightweight. There's no point trying to preload a font file of 20Kb by displaying a graphic of 4Mb..

Now, if we load our page, all the content is hidden, apart from the html.wf-loading with its loader gif background. When the font loads, that gif will vanish.


Bring it Back

The html element has now been assigned other classes, so let's use those to bring back the invisible content:

.wf-active *, 
.wf-inactive * {
	/*
	add some transitional effects
	to reintroduce the content
	gradually once fonts are loaded
	*/
	-webkit-transition: opacity 1s ease-out;  
	-moz-transition: opacity 1s ease-out; 
	-o-transition: opacity 1s ease-out;  
	transition: opacity 1s ease-out;  
}

Irrespective of whether the font was successfully or unsucessfully loaded, we'll need to see our content again. wf-loading releases its grasp on the zero opacity of all elements on the page, so we transition them slowly back in. Again, to slow things down, try adding loads of fonts (or play with the class names in your browser's element inspector.) Fonts are also stored, so each time you test it you may need to empty your browser's cache.


Conclusion

Simple, yet effective. My favorite kind of tip. And the possibilities are endless - how would you suggest using the wf-* classes?

Last, but not least, I couldn't resist this preloader by Kontramax on dribbble. It's a bit heavy for our purposes, but what the hey!

Related Posts