Paul Irish

Making the www great

Fighting the @font-face FOUT

FOUT is what I’m calling the flash of unstyled text that you get while using @font-face in Firefox and Opera.

Heads up, lots of things have changed around this stuff. check out all the updates on this post!

In June, Remy Sharp documented the how a browser progressively renders a page using @font-face. Things work differently between browsers natch:

Here’s how in Firefox; basically the text is in a default webfont until the custom font is ready:

Webkit takes a very different approach, and very intentionally. They believe it’s better to keep the text invisible until the font is ready. This way, there is no moment where the text flashes into its newly upgraded self. (This moment should be familiar to you if you’ve used sIFR)

I really don’t like the text upgrade FOUT, so I personally prefer webkit’s technique. But either way, we want the font loaded ASAP, so let’s speed it up!

Best practices for serving fonts:

  • Minimize the overall kilobyte size of your font file. You can reduce the size of your font file by subsetting it (more on this later).
  • Heavy caching via a far-future expires header.
  • Gzip? Well, no; you can’t gzip a font file, though you can gzip a css file that holds the data-uri representation, but you don’t get much gain there. It’d primarily be an obfuscation technique.Stoyan Stefanov has done some excellent research into @font-face and gzip. Summary: It’s possible! 40-45% savings. Do It!

When exactly do browsers download the font file?

Garrick at Kernest tipped me off to IE’s interesting behavior here.

After some research we can see when the asset download is initiated:

  • IE will download the .eot file immediately when it encounters the @font-face declaration.
  • No browsers download the font file when they find a css rule that references the @font-face font.
  • Gecko, Webkit, and Opera all wait until they encounter HTML that matches a CSS rule with a fontstack including the @font-face font.

I’ve put up a test page where you can experiment and watch your dev tools to see when the file is grabbed.

In what cases will you get a FOUT
  • Will: Downloading and displaying a remote ttf/otf/woff
  • Will: Displaying a cached ttf/otf/woff
  • Will: Downloading and displaying a data-uri ttf/otf/woff
  • Will: Displaying a cached data-uri ttf/otf/woff
  • Will not: Displaying a font that is already installed and named in your traditional font stack
  • Will not: Displaying a font that is installed and named using the local() location

Defeat the Firefox FOUT entirely #1: hide the page

The one serious caveat to this technique is: The page will not be visible until all content, iframes, remote scripts, fonts, and images are downloaded. for a maximum of three seconds (I added a three second bailout condition, read below.)

This should run in the <head> somwhere:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(function(){
  // if firefox 3.5+, hide content till load (or 3 seconds) to prevent FOUT
  var d = document, e = d.documentElement, s = d.createElement('style');
  if (e.style.MozTransform === ''){ // gecko 1.9.1 inference
    s.textContent = 'body{visibility:hidden}';
    var r = document.getElementsByTagName('script')[0];
    r.parentNode.insertBefore(s, r);
    function f(){ s.parentNode && s.parentNode.removeChild(s); }
    addEventListener('load',f,false);
    setTimeout(f,3000);
  }
})();

// a nice improvement to this script is to only hide the elements using webfonts 
// with visibility:hidden instead of the entire <body>
// that's up to you to select them in that textContent line, though
2011.11.17 Updated to change stylesheet injection method, fixing a FF4 bug.

2011.04.14 Added note about better technique through targeted selection

First, we are detecting if we’re firefox 3.5+ by seeing if -moz-transform is supported, which was added at the same time. We use visibility:hidden instead of display:none, so that the font will actually be requested, and we remove that style once the page has finished loading. We’re hinging on window load to be our re-entry point, because as Steve Souders pointed out, “font files block the window’s onload event from firing in IE and Firefox, but not Safari nor Chrome.”

I’ve also added a 3 second bailout condition; this means if the page has not completely loaded in three seconds, we’re going to show it anyway. It’s possible the font won’t be ready, but unlikely, I believe. This aims to solve the issue Remy found with the Standards.next site. I wouldn’t recommend it, but you can disable this behavior by commenting out the setTimeout line.

Defeat the Firefox FOUT entirely #2: hide the text

I posted this over on html5rocks.com’s tutorial: Quick Guide to Implement Webfonts via @font-face.

Accompanying the Google Font API is the WebFont Loader, a javascript library aiming to provide a number of event hooks giving you a lot of control over the loading. Let’s take a look at how you can get other browsers to mimic WebKit’s behavior of hiding the fallback text while the @font-face font loads.

1
2
3
4
5
6
7
8
9
<script src="//ajax.googleapis.com/ajax/libs/webfont/1/webfont.js"></script>
<script>
WebFont.load({
  custom: {
    families: ['Tagesschrift'],
    urls : ['http://paulirish.com/tagesschrift.css']
  }
});
</script>
1
2
3
4
5
6
7
8
/* we want Tagesschrift to apply to all h2's */
.wf-loading h2 {
  visibility: hidden;
}
.wf-active h2, .wf-inactive h2 {
  visibility: visible;
  font-family: 'Tagesschrift', 'Georgia', serif;
}

If JavaScript is disabled, the text will remain visible the whole time, and if the font errors somehow, it’ll fall back to a basic serif safely. Consider this a stop-gap measure for now; most webfont experts desire hiding the fallback text for 2-5 seconds, then revealing it. Low-bandwidth and mobile devices benefit greatly by this timeout. Understandably, Mozilla is looking to rectify this soon.

A more lightweight but less effective solution is the font-size-adjust property, currently only supported in Firefox. It gives you an opportunity to normalize x-height across a font-stack, reducing the amount of visible change in the FOUT. In fact, the Font Squirrel generator just added a feature where it tells you the x-height ratio of the fonts you upload, so you can accurately set the font-size-adjust value.

2009.11.07. Added the Defeat the Firefox FOUT section.

2009.11.08. Tweaked defeat FOUT code to have a 3 second bailout.

2009.12.14. Added the In what cases will you get a FOUT section.

2010.05.03 font-size-adjust (only supported in Firefox) normalizes x-height and may improve the FOUT.

2010.05.26: I removed a bunch of old stuff from this article; it was kinda outdated.

2010.08.24: I updated this article with how to prevent FOUT using the Google Font API’s WebFont Loader.
Take a look at some of my other (recently updated) webfont stuff:
2011.04.14: superquick updates on FOUT! read on:
  • Firefox (as of FFb11 and FF4 Final) no longer has a FOUT! Wooohoo! http://bugzil.la/499292 Basically the text is invisible for 3 seconds, and then it brings back the fallback font. The webfont will probably load within those three seconds though… hopefully..
  • IE9 supports WOFF and TTF and OTF (though it requires an embedding bit set thing– mostly moot if you use WOFF). HOWEVER!!! IE9 has a FOUT. :(
  • Webkit has a patch waiting to land to show fallback text after 0.5 seconds. So same behavior as FF but 0.5s instead of 3s.

And… WebInk has written a small script called FOUT-B-GONE which takes these facts into account and helps you hide the FOUT from your users in FF3.5-3.6 and IE.

Pretty sweet!

2012.11.18: Like two years ago I also wrote Quick Guide to implement webfonts via @font-face which has a DEALING WITH FOUT section you should read.

Comments