How to Improve Page Performance with a Font Loader

Craig Buckler
Share

A big thanks to Jason Pamental for the inspiration to write this article. I’d never have considered the issue otherwise!

When was the last time you used Arial, Times New Roman, Helvetica or … shudder … Comic Sans in your web pages? Web fonts took too long to arrive but, once they did, we never looked back. Fonts are fun, (often) free and fast to implement:

@import url(http://fonts.googleapis.com/css?family=Ubuntu:300,300italic,400,400italic,500,500italic,700,700italic);

You can then use the font throughout your pages, e.g.

body {
	font-family: Ubunutu, sans-serif;
	font-weight: 400;
}

The fonts also work in mobile devices so users get a great experience in your Responsive Web Design.

Or do they?

After images, fonts are the normally the largest assets in your web page. The Ubuntu font above adds almost 250Kb to the page weight which is noticeable on slower mobile connections. Chrome, IE, Safari and Opera leave a blank space while the font is loaded so the page is unusable. Firefox and older versions of Opera show text in a fallback font then switch — known as a Flash of Unstyled Text (FOUT). Neither option is ideal.

We rarely worry about font weight problems and make excuses such as “it’s only an issue on the first page” or “many users will have the font cached”. We may omit lesser-used fonts; for example, removing most of the Ubuntu italic styles saves almost 40%. Few dare to take the obvious solution of using standard OS fonts — our clients and designers would never forgive us.

The JavaScript webfontloader

Fortunately, there is another option: the webfontloader. This JavaScript library can load fonts from Google, Typekit, Fonts.com, Fontdeck or your own server in the background once the page has loaded. The library itself adds a further 17Kb to the page but it is also downloaded as a background process.

To load the Ubuntu font set above, we create a global object named WebFontConfig which defines our fonts and settings then load the webfontloader itself:

var WebFontConfig = {
	google: {
		families: [ 'Ubuntu:400,300,400italic,300italic,500italic,500,700,700italic:latin' ]
	},
	timeout: 2000
};

(function(){
	var wf = document.createElement("script");
	wf.src = ('https:' == document.location.protocol ? 'https' : 'http') +
		'://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
	wf.async = 'true';
	document.head.appendChild(wf);
})();

We can therefore determine whether none, some or all fonts are loaded depending on the device and bandwidth capacity. Ideally, we could use the Network Information API but browser support remains limited. Alternatively, note the timeout setting in WebFontConfig; if the font files require more than two seconds to download, the request is abandoned.

CSS Callbacks

The webfontloader applies class names to the html element during operation:

  • .wf-loading — all fonts have been requested
  • .wf-active — all fonts are available
  • .wf-inactive — none of the fonts could be loaded

Classes are also applied for individual fonts:

  • .wf-<familyname>-<fvd>-loading — a single font has been requested
  • .wf-<familyname>-<fvd>-active — a single font is available
  • .wf--<familyname>-<fvd>-inactive — a single font could not be loaded

where <familyname> is a sanitized version of the font name and <fvd> is a variation description such as i4 for 400 weight italic.

This permits us to switch fonts once they have downloaded — in the same way Firefox operates, e.g.

/* default OS fonts */
body {
	font-family: arial, sans-serif;
}

/* fonts now loaded */
.wf-active body {
	font-family: 'Ubuntu';
}

JavaScript Callbacks

Similar JavaScript callback functions can be defined in the WebFontConfig although there are fewer situations where this is useful, e.g.

var WebFontConfig = {
	google: {
		families: [ 'Ubuntu:400,300,400italic,300italic,500italic,500,700,700italic:latin' ]
	},
	timeout: 2000,
	loading: function() {},
	active: function() {},
	inactive: function() {},
	fontloading: function(familyName, fvd) {},
	fontactive: function(familyName, fvd) {},
	fontinactive: function(familyName, fvd) {}
};

For more information, refer to the webfontloader documentation.

Minimizing FOUT

The Flash of Unstyled Text is jarring if your fallback font is significantly different in style, weight or spacing to your web font. However, with a little experimentation you can adjust the fallback font, weights, line-heights and margins to ensure page elements remain in approximately the same location when the web font is loaded…

See the Pen How to use a font loader by Craig Buckler (@craigbuckler) on CodePen.

Click the TOGGLE FONT button to see the font-switching effect. The change isn’t completely unnoticeable but, importantly, the user wouldn’t lose their place if they’d started reading.

You can add a TOGGLE FONT button to any page to help you assess suitable fallback styles:

<button onclick="document.documentElement.classList.toggle('wf-active');return false;">toggle styles</button>

In summary: font use may be free, but try to minimize the cost to the user. If you’re loading a megabyte of font files, your lovingly-created RWD layout isn’t suitable for mobiles!