Waiting for web fonts to load

posted on August 2, 2012
****Since writing this post, I have created a better way to identify when web fonts have been loaded and wrote a new blog post about it.

While working on a project where I was required to sample dimensions of HTML elements with specific web fonts, I have bumped into a problem. There was no DOM event signaling when particular fonts were loaded and rendered. And even though all the fonts were base64 encoded and encoded into the web page. The browser didn't render them immediately. There was a slight delay between the first-page render and fonts rendering.

After a short research, I have found a hint in typekit’s blog. The solution presented in that post was to create an off-screen element, one for each font, with a bit of text and appropriate font-family value. Then periodically compare that element width to a reference width. Once element width changes, we can say that font is loaded and rendered.

And because I could not use 3rd party dependencies, I wrote a short onFontsLoad function that implements a similar solution. This function receives an array of strings representing required font families and a callback function that is invoked when all passed fonts are loaded and rendered:

Loading gist https://gist.github.com/smnh/1bc5aaead6ce52c39e9e

The onFontsLoad function also gets a third, optional parameter, which is an object with two fields:

  1. maxNumOfTries – maximum number tries to retrieve and compare the element dimension.
  2. tryIntervalMs – interval in milliseconds between retrieving and comparing the element dimension.

The onFontsLoad function iterates over the passed font-families array. For every font-family, it creates an element with a pangram text, and it applies a style with a matching font-family. It also creates one element with the "serif" font and stores its dimensions for reference. The pangram ensures that a change in size will occur even if the dimension of a single character of the requested font is different from the "serif" font. The font-size that is used on all the elements is 40px. This ensures that even a slight font appearance changes the element's size. Then, it polls the dimensions of the elements. When the dimensions of all the elements have been changed, the callback is invoked. However, the callback is invoked anyway if some fonts are still not loaded after a specific time (maxNumOfTries * tryIntervalMs).

The callback is executed with a single error parameter. This parameter would be null if all fonts were successfully loaded. Otherwise, this parameter will be an object with a message property with an error message and additional notLoadedFontFamilies property with an array of font-families that weren't loaded.

Here is a usage example:

// Show some loading indicator while fonts on a page are loaded
onFontsLoad(["myFont1", "myFont2"], function(error) {
    // Hide loading indicator and show elements with loaded fonts