FOUT is what I'm calling the flash of unstyled text that you get while using @font-face in Firefox and Opera.
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
Let's get the font ASAP
The sooner the better, so let's prioritize getting this font before everything else.
We'll set up our @font-face declaration:
/* chunk will load immediately in IE at this declaration*/
@font-face {
font-family: 'ChunkFive Regular';
src: url('fonts/Chunkfive.eot');
src: local('ChunkFive Regular'), local('ChunkFive-Regular'), url('fonts/Chunkfive.otf') format('opentype');
}
/* define a class that uses this font */
.chunk { font-family:'ChunkFive Regular'}
And inside the <head>, we'll include this:
(function(className){
// quit early if we're in IE, no need to do any of this.
if (/*@cc_on!@*/0) return;
var f = document.createElement('fontdl');
f.innerHTML = 'fontdl';
// associate with the @font-face declaration and hide it
f.className = className;
f.style.cssText = 'position:absolute; visibility:hidden'
// it's still off-DOM so it doesn't download yet
// document.body doesnt exist yet so we'll add it onto the HTML tag
document.documentElement.appendChild(f);
// font download initiated Now.
// let's clean up after ourselves (opera needs a timeout > 0)
setTimeout(function(){f.parentNode && f.parentNode.removeChild(f)},100)
})('chunk'); // <== pass in the class here.
2009.10.10: Based on a tip from my colleague
Adam McIntyre, we have a more elegant solution than the above javascript. It, along with more fontstack research, is as follows…
Rather than creating an element on the fly that uses the font, we do the same with HTML:
Adam postulated the we could do the same trick by classing the HTML tag:
(e.g. <html class="chunk">)
- The font-family style won't actually cascade, so no worries about it being inherited by your content
- This works in Gecko and Opera, but not Webkit
Alternatively, we add an applicable element to the head:
<b class="chunk" style="position:absolute; visibility:hidden">download please</b>
- Works in webkit, gecko, opera. Waa hoo!
- Obviously this doesn't validate. FYI, The element will be thrown into the <body> on page load.
Can I pre-load all the font assets?
So let's say we have more than one @font-face declaration:
@font-face { font-family: 'ChunkFive Regular'; src: local('ChunkFive Regular'), url('fonts/Chunkfive.otf') format('opentype'); }
@font-face { font-family: 'League Gothic'; src: local('league gothic'), url('fonts/LeagueGothic.otf') format('opentype'); }
If we set a new class that references both new fonts in a single fontstack, and then pass use that class for our above techniques:
- Gecko retrieves all webfonts mentioned in the font stack.
- Opera retrieves all webfonts mentioned in the font stack.
- IE, as mentioned, retrieves them when they're declared, not used.
- Webkit retrieves each font mentioned sequentially until it finds a working one.
- 404s and invalid files are considered non-working, of couse.
So with some CSS like so:
.chunk { font-family:'ChunkFive Regular'}
.league { font-family:'League Gothic'}
.allfonts { font-family: 'ChunkFive Regular', 'League Gothic'; }
<!-- preloads both fonts in gecko and opera, webkit only gets the first -->
<b class="allfonts" style="position:absolute; visibility:hidden">download please</b>
<!-- preloads all the fonts in the fontstack in gecko, opera, and webkit -->
<b class="chunk" style="position:absolute; visibility:hidden">download please</b>
<b class="league" style="position:absolute; visibility:hidden">download please</b>
Is this the end-all be-all solution to quick load and FOUT?
Nope. As Jonathan Snook pointed out in the comments, these won't elimate seeing the fallback font FOUT in Gecko and Opera, they only prioritize the load of those fonts. As we know, browsers have a limit of concurrent connections, so we're using these tricks to get the fonts first in line.
Also, This is really only for the initial time, because after that, your far-futures expire header means the ttf stays cached locally, no more requests needed.
I'm not sure if we'll be able to use webkit's transparent font load in Gecko in any graceful way. (It's possible with a sniff and polling, but that seems like overkill) I'm also not sure if we'll get Gecko's load technique in Webkit, which would be optimal for slow/mobile connections. For the time being your time is best served getting the font size very small, gzipping it, prioritizing it first, and caching it for a while.
Defeat the Firefox FOUT entirely
A little bit ago, Typotheque posted a technique aiming to avoid the FOUT. Using jQuery, they hide the body on dom ready, and then reveal it at the window load event.
The posted technique doesn't work as:
- It targets all users, but we should only tweaks things for Firefox 3.5+ users.
- Users will actually see the text before it's hidden during at dom ready.
- As was mentioned earlier, fonts are downloaded when text appears in the page that the font will apply to. Therefore, anything hidden with
display:none will not request the font file.
- Not everyone has jQuery, so let's go with something more general
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:
(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}';
e.firstChild.appendChild(s);
function f(){ s.parentNode && s.parentNode.removeChild(s); }
addEventListener('load',f,false);
setTimeout(f,3000);
}
})();
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.
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.