Archive for February, 2012

Web Font Performance: Weighing @font-face Options and Alternatives

Feb ‘12 27

Web fonts are a key ingredient in today's website designs; at my employer (AOL) it is a given redesigns will feature downloadable fonts. The days of maintaining a sprite full of graphic text headlines are behind us. We’ve moved on—but what approach yields the best performance?

The goal of this article is to look at the various web font implementation options available, benchmark their performance, and arm you with some useful tips in squeezing the most bang for your font byte. I will even throw in a new font loader as a special bonus!

Font Hosting Services vs. Rolling Your Own

There are two approaches you can take to get licensed, downloadable fonts on to your web pages: font hosting services and do-it-yourself (DIY).

Font Hosting Services like Typekit, Fonts.com, Fontdeck, etc., provide an easy interface for designers to manage fonts purchased, and generate a link to a dynamic CSS or JavaScript file that serves up the font. Google even provides this service for free. Typekit is the only service to provide additional font hinting to ensure fonts occupy the same pixels across browsers.

The DIY approach involves purchasing a font licensed for web use, and (optionally) using a tool like FontSquirrel's generator to optimize its file size. Then, a cross-browser implementation of the standard @font-face CSS is used to enable the font(s). This approach ultimately provides the best performance.

Both approaches make use of the standard @font-face CSS3 declaration, even when injected via JavaScript. JS font loaders like the one used by Google and Typekit (i.e. WebFont loader) provide CSS classes and callbacks to help manage the "FOUT" that may occur, or response timeouts when downloading the font.

What the FOUT?

FOUT, or “Flash of Unstyled Text,” was coined by Paul Irish and is the brief display of the fallback font before the web font is downloaded and rendered. This can be a jarring user experience, especially if the font style is significantly different.

FOUT of some form exists in all versions of Internet Explorer and Firefox 3.6 and lower. Check out the video of my demo below (preferably in full screen mode) at the 1.6 second mark to see it in action:

You'll notice in Internet Explorer 9, the content is blocked until the image has downloaded. Your guess is as good as mine.

Here are my recommendations for avoiding the FOUT:

  • Host the fonts on a CDN
  • GZIP all font files except .woff (already compressed)
  • Cache all font files for 30+ days by adding a future expires cache header
  • Remove excess glyphs (characters) from the font files
  • Ensure @font-face is the first rule of the first stylesheet on the page (IE)
  • Still have a FOUT? Read on, a JavaScript font loader may be in order.

Removing Excess Font Glyphs

Font Squirrel has an awesome tool that lets you take a desktop font file and generate its web counterparts. It also allows you to take a subset of the font, significantly reducing file size.

To show just how significant, I added Open Sans and tried all three settings:

Glyphs Size
Basic 940 66.9 KB
Optimal 239 20.9 KB
Expert 119 13 KB

From the table above, it should be obvious that the byte size is directly correlated to the # of glyphs (characters) in the font file.

I suggest you follow along with me at www.fontsquirrel.com/generator!

The Basic setting leaves the characters untouched. Optimal reduces the characters to around 256, the Mac Roman character set. We are able to see the greatest savings by selecting Expert mode and only including the Basic Latin set, then manually adding in characters we need.

  • Under Rendering, uncheck Fix Vertical Metrics
  • Under Subsetting, check Custom Subsetting...
  • Under Unicode Tables, check only Basic Latin
    Note: This assumes the fonts will only use English characters; for other languages add the characters you need.
  • If you are typography nerd, copy and paste ‘ ’ “ ” into the Single Characters field
  • Verify your Subset Preview; adjust if needed
  • Under Advanced Options, give your font a suffix based on the subset (i.e. latin)

JavaScript Font Loaders

Typekit and Google joined forces to create an open source WebFont Loader that provides CSS and JavaScript hooks indicating a font's status as it downloads. This can be useful in normalizing the FOUT across browsers by hiding the text and adjusting CSS properties so that both fonts occupy the same width.

The three states it tracks are loading, active, and inactive (timeout). Corresponding CSS classes (wf-loading, wf-active, and wf-inactive) can be used to control the FOUT by first hiding headings and then showing them when once downloaded:

h1 {
    visibility: hidden;
}
.wf-active h1 {
    visibility: visible;
}

JavaScript hooks for these same events are also available via callbacks in the configuration object:

WebFontConfig = {
    google: {
        families: [ 'Tangerine', 'Cantarell' ] // Google example
    },
    typekit: {
        id: 'myKitId' // Typekit example
    },
    loading: function() {
        // JavaScript to execute when fonts start loading
    },
    active: function() {
        // JavaScript to execute when fonts become active
    },
    inactive: function() {
        // JavaScript to execute when fonts become inactive (time out)
    }
};

The WebFont loader also includes callbacks for fontactive, fontloading, and fontinactive that is fired each time a font updates, giving you control at a font level. For more information, check out the WebFont Loader documentation.

Introducing Boot.getFont, a fast and tiny Web Font Loader

I haven't seen one out there (leave a comment if I missed it) so I wrote a little font loader that provides the same hooks for loading fonts called getFont as part of my Boot library.

It weighs in at 1.4 K after GZIP (vs. 6.4 KB Google, 8.3 KB Typekit) and easily fits into your existing library. Simply change the "Boot" string at the end of the file to update the namespace (i.e., jQuery).

Fonts are loaded via a JavaScript function, and a callback can be supplied that executes once the font has finished rendering.

Boot.getFont("opensans", function(){
    // JavaScript to execute when font is active.
});

Boot.getFont provides similar CSS classes to the WebFont Loader but at a font level, affording precise control:

.wf-opensans-loading {
    /* Styles to apply while font is loading. */
}
.wf-opensans-active {
    /* Styles to apply when font is active. */
}
.wf-opensans-inactive {
    /* Styles to apply if font times out. */
}

You can easily configure it to grab fonts based on your directory structure by loading a configuration object:

// Global
Boot.getFont.option({
    path: "/fonts/{f}/{f}-webfont" // {f} is replaced with the font name
});

// Font-specific
Boot.getFont({ path: "http://mycdn.com/fonts/{f}/{f}-wf" }, "futura" );

I haven’t had time to document all the goods, but the library is available here if you are interested.

Gentlefonts, start your engines!

Now that we are armed with the knowledge needed to ensure fast-loading fonts, let us take a look at the performance of the implementation options.

I set up the following test pages, loading the same web font (Open Sans), spanning DIY and various hosting options at Typekit and Google:

  • System: Our control test; this page does not load any fonts and uses Arial.
  • FontSquirrel Optimal: FontSquirrel generator’s recommended ‘Optimal’ setting and FontSpring’s cross-browser @fontface declaration. Fonts hosted on the same server as the web page like most small websites.
  • FontSquirrel Expert: Used recommended tips above to trim font file size using the FontSquirrel Generator, I replaced the ‘Optimal’ font kit in the above test with a minimal ‘Basic Latin’ character set.
  • FontSquirrel Expert (CDN): Same as the above test, however fonts are hosted from a CDN on a different domain.
  • Boot.getFont: This test updated the ‘FontSquirrel Expert’ test to use my Boot.getFont JavaScript library.
  • Boot.getFont (CDN): Same as Boot.getFont test, except font files are hosted from a CDN on a different domain.
  • Google Web Fonts Standard: I chose Google to represent a free font hosting service, and since this is a speed test, and Google is all about speed, I figured they should be in the race. Google provides 3 implementation options, this being the default—a <link> element pointing to a dynamic stylesheet that loads the font(s). Note: I left out the ‘Import’ option as results were nearly identical to ‘Standard’ option.
  • Google Web Fonts JavaScript: This option includes the WebFont loader discussed above to load the fonts, hosted from Google’s servers.
  • Typekit: Here, I created a kit at Typekit and used the options that provided the smallest font file.

I used webpagetest.org and loaded each test page 10 times in Chrome, Firefox 7, IE7, IE8, and IE9 over a 1.5 mbps DSL connection. We are comparing implementation, so I took the fastest test to weed out network latency issues and other causes of variance in the data.

Here is how they stack up, ranked by the fastest time (ms) across browsers:

Fastest Load Times (ms) by Implementation and Browser
IE9 IE8 IE7 Firefox Chrome Fastest
System 373 358 370 506 398 358
Boot.getFont (CDN) 692 697 696 652 680 652
FontSquirrel Expert (CDN) 710 697 681 667 681 667
Boot.getFont 812 698 798 693 704 693
FontSquirrel Expert 822 704 784 802 792 704
Typekit 798 999 959 795 815 795
FontSquirrel Optimal 997 800 803 933 925 800
Google Web Fonts JavaScript 1096 1097 1126 1254 801 801
Google Web Fonts Standard 896 850 870 1003 899 850

Take some time to digest the data. To better compare implementations across browsers, check out these charts:

IE 9

Font Implementation Benchmarks: Internet Explorer 9

IE 8

Font Implementation Benchmarks: Internet Explorer 8

IE 7

Font Implementation Benchmarks: Internet Explorer 7

Firefox

Font Implementation Benchmarks: Firefox

Chrome

Font Implementation Benchmarks: Chrome

My Observations

The Do-It-Yourself implementations were consistently the fastest, especially when combined with a CDN. This is due to physics—less bytes, requests, and CPU overhead are required to serve the font.

It is interesting to compare Google Web Fonts (GWF) to Typekit since they use the same core loader, but that is where the similarities end:

Google Web Fonts in Firefox (1254ms): JS » CSS » Font

Typekit in Firefox (795ms): JS » CSS Data URIs

In browsers that support them, Typekit uses Data URIs in the CSS to load the font, whereas GWF first loads the JS, then the CSS, and finally the font. Typekit uses this approach in IE 8 and lower where Data URIs are not supported, ending up with slower load times in those browsers.

Google is also slower because of their multiple DNS lookups; Typekit rightly uses one domain for all assets.

I was impressed by the performance of Boot.getFont, which ended up being faster (sometimes by a hair, sometimes more) than the standard @font-face CSS in all cases. My hypothesis is that somehow the JS triggers a reflow/repaint that forces the fonts to download sooner in all browsers.

Final Thoughts

While this article could probably be split into several, I wanted a single place to document implementation choices, tips for optimizing them, and have some reference benchmarks. If other font providers want to hook me up with a free account (and host Open Sans, for consistency), I’d be happy to include them in another study at another time.

I was again dissappointed to see Google turn out another slow service. Google friends, take some notes from Typekit!

I am looking forward to hearing your thoughts and observations on this experiment, and to your recommendations for speeding up web fonts. Thanks for reading!

Please index me, experiment!

“I’m ready to go in, Coach, just give me a chance. I know there’s a lot riding on it, but it’s all psychological. Just gotta stay in a positive frame of mind.” — Ace Ventura