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

Bookmark and Share

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!

Bookmark and Share

27 Responses to “Web Font Performance: Weighing @font-face Options and Alternatives”

Leave a Reply »

  1. Aaron Peters lessoned... February 28th, 2012 at 2:27 am

    Dave,

    excellent article/research.
    Questions:
    1) what CDN did you use for Boot.getFont (CDN) and FontSquirrel Expert (CDN)
    2) are you sure the CDN was actually serving the file (cache HIT)?
    3) did you serve the files Gzipped from the CDN?
    4) what Webpagetest.org location did you use?

    - Aaron

  2. Andy Davies notified... February 28th, 2012 at 2:47 am

    Funnily enough I’ve just been analysing a site for a client and I found that Typekit was adding 0.5s to the pre-render time in IE9

    Even though the versions of pre-IE9 versions use a separate font file, I was seeing earlier render start times as the font downloading doesn’t block render start in the same way that the CSS/datauri based approach does.

    Thanks for the article it fills in some of the gaps I have on the font stuff

  3. ArtzStudio howled... February 28th, 2012 at 8:16 am

    @Aaron – Thanks!

    1) Akamai
    2) Yup, since I took the fastest run of 10 in the results
    3) Yes.
    4) Dulles, VA (East Coast USA)

    @Andy – In my experience, @fontface does not block rendering – in fact, that is why we have a FOUT. I’d be curious to hear more.

  4. Some links for light reading (29/2/12) | Max Design muttered... February 28th, 2012 at 10:56 am

    [...] Web Font Performance: Weighing fontface Options and Alternatives [...]

  5. Brad Dunzer lessoned... February 28th, 2012 at 11:46 am

    Dave,

    Very excellent article breaking down the differences in web font service loading and self-hosting. You missed our FOUT-B-GONE script that we wrote a year ago to automatically handle FF3.6 and IE9. http://www.extensis.com/en/WebINK/fout-b-gone/index.jsp – check it out.
    One thing you also need to note about self-hosting over services like Typekit, WebINK and others is rendering fonts in browsers can be a crazy mess at times. If the font is not built correctly fonts can stop rendering in a new version of browser. It is why each of our services have invested heavily into testing fonts before they go live and continue testing when new browsers arrive in the Alpha and Beta channels. Beyond that you also need to consider that services can deliver fonts optimized for OS/Browser combinations that standard self-hosting stacks cannot do. For instance Google sends fonts without hinting to Mac and iOS devices making the fonts sometimes 50% smaller. Typekit began a while ago sending WOFF/CFF instead of WOFF/TFF fonts to Windows computers to render cleaner looking fonts. And our Service WebINK will begin very soon doing both of these offerings and more in a very short time frame. We have also just introduced a new method of requesting fonts that bundles up all font requests into a single call, thus reducing the network traffic between a browser and our servers.

    So while self-hosting a font file might appear faster in some testing it might not be the best solution always.

  6. Andy Walpole hazarded... February 28th, 2012 at 12:11 pm

    It’s an interesting experiment. There’s little difference between my solutions of choice, FontSquirrel and Typekit. It would interesting to repeat the exercise on various mobile platforms.

  7. Jon Kemp notified... February 28th, 2012 at 12:13 pm

    We are hosting our webfont files on a separate server that uses Akamai for caching, and the fonts do not work on Firefox and IE. I know that the Firefox problem is because of the cross domain policy. How do you implement webfonts on a CDN but still get around the cross domain origin policy?

  8. Matti Schneider blurted... February 28th, 2012 at 12:50 pm

    Very good article.

    One thing, though: I believe you’re missing an important point, or at least a notice, in the FontSquirrel “Expert mode” tutorial.

    Indeed, for English-only content, with an English-only audience, the set of characters you gave is sufficient. However, remember most other languages use accented letters. And, IMHO, the few kb lost in adding accented characters are much worth the gains in maintainability. Even English content may use foreign phrases, or may quote one at some point. As a single example, “déjà vu” (French expression) is written “déjà vu”, not “deja vu”. If you’re in a use case where you care enough about typography to embed your own fonts, you most probably care enough to spell foreign words properly.

    I would not like to be the one in charge of adding elements to the charset, re-generating *all* font files, testing, and adding cache busting to _font-files_ every time a writer needs one foreign glyph ;)

  9. ArtzStudio announced... February 28th, 2012 at 1:32 pm

    @Brad – The FOUT-B-Gone test page threw an error in IE8 when I went to try it out. I was also against the approach of waiting until all stylesheets were downloaded and then parsing their cssText using RegEx, then performing the hide and show of the text when ready — it struck me as inefficient and having unintended rendering consequences. Re: bundling fonts together, I’d worry that in serving them together they may not all be used on the page, wasting bytes; larger files also are subject to cache limits on mobile, something else we need to watch out for. I’d be curious to see Google’s unhinted fonts and their byte savings; exporting fonts without hinting in the FontSquirrel Generator did not yield savings (but I did notice Google’s EOTs were not hinted and gross looking, something I meant to mention in the article).

    @Andy – Thanks for the suggestion, I’ll look into mobile testing.

    @Jon – You need to serve the fonts with the Access-Control-Allow-Origin header.

    @Matti – Great catch, I meant to point this out in the article, although I want to get people thinking harder about including only what they need, as the savings can quickly add up. Thanks!

  10. AskApache tipped... February 28th, 2012 at 8:56 pm

    I havent seen a real article like this one in ages, fantastic work… bookmarked

  11. Jason Featheringham reckoned... March 1st, 2012 at 4:53 pm

    We are just now beginning to utilize @font-face in any redesigns. These are great tips to improve the experience–thanks!

  12. Steven Wilson twisted... March 2nd, 2012 at 3:24 am

    Great article, I noticed you didn’t test in safari was there a reason for that ?

  13. Johann proclaimed... March 2nd, 2012 at 5:54 am

    I’ve seen many webpagetest.org graphs of sites that use Google’s font CDN with themes.googleusercontent.com slowing down page load times a lot. This could be because Google serves full fonts (which, as you’ve observed, is rarely needed), but I’m also suspecting that Google throttles themes.googleusercontent.com to a bandwidth of around 50 KB/s — I have never seen a faster download speed in any graph I’ve looked at.

    Just speculation? I don’t know, but from the graphs I’ve seen, I wouldn’t recommend Google’s font hosting for now.

  14. Friday Focus 03/02/12: Tentacular | Devlounge tipped... March 2nd, 2012 at 6:05 am

    [...] CSS, Performance – Web Font Performance: Weighing @font-face Options and Alternatives “The goal of this article is to look at the various web font implementation options [...]

  15. ArtzStudio posted... March 2nd, 2012 at 8:24 am

    @Steven – Safari is not available at webpagetest.org, we will have to bug Pat Meenan to get on that.

  16. Today’s Readings | Aaron T. Grogg exacted... March 2nd, 2012 at 3:52 pm

    [...] Dave Artz to be one of the smarter people on the web. And when he writes, I read. Interesting findings on web performance with regards to web fonts. Also interesting to me is how hot the topic of web fonts was in late-2011-early-2012, and how fast [...]

  17. karl pontificated... March 5th, 2012 at 7:15 am

    Just a minor detail but the “Under Unicode Tables, check only Basic Latin” is only recommended for people who are writing in English. In all languages with accents, you can’t just do that. Even worse in languages such as Chinese or Japanese. I would change it to

    “Under Unicode Tables, check only Basic Latin in you only use English. You might need more characters for your own language.”

    for the rest, useful article

  18. karl stuttered... March 5th, 2012 at 7:17 am

    Ah forgotten. Have you tried with Opera? and Opera Mobile?

  19. ArtzStudio reported... March 5th, 2012 at 7:56 am

    @karl and @Matti – Thanks for pointing out the language issue, see my edits to the article.

  20. ArtzStudio posted... March 5th, 2012 at 7:58 am

    @karl – webpagetest.org does not include Opera or mobile in its testing, so I am not sure how I could get this data (for free).

  21. mike foskett warned... March 5th, 2012 at 9:26 am

    Brilliant article.
    Covered all my concerns regarding implementing web-fonts at Tesco.
    Off the back of this article I’ll start running a few of my own tests.

  22. Andy Davies squawked... March 12th, 2012 at 6:29 am

    @artzstudio

    If you look at the waterfall for typekit – http://www.webpagetest.org/result/111231_2K_2PNEM/10/details/

    StartRender doesn’t happen until after the font arrives from Typekit…

  23. Jamund Ferguson announced... March 13th, 2012 at 1:20 pm

    In my personal tests I’ve found that the fastest way forward is to base64 a single WOFF font (dropping IE8 support) and put it in your CSS file. It’s insanely fast.

  24. Brad Dunzer hazarded... March 21st, 2012 at 5:00 pm

    Dave,
    Thanks for the notes about fout-b-gone. Yes it was built to handle the simple approach so it had some trade-offs.

    Regarding the bundling I mentioned. Its not that we are bundling the fonts together but the first request for them. Prior to our change we had users place a @font-face link for each font required in their CSS. Now one link makes a call for all of the fonts. Actually it makes a call for a dynamic CSS generation that writes the @font-face calls to the page and gets the fonts.

    One thing i was wondering in your comparison of services (google and typekit) how did you make sure that the font file sizes were the same? Each vendor can do specific things to a font and sizes can vary wildly for the same font face. But its pretty easy to see why the font for typekit comes back faster when the base64 version is returned with the CSS and thus there is no third step as is shown for Google. Did you also test based on downloading multiple fonts at once. Say with 4 font-faces which is a typical setup for a single font? It would be interesting to see how that larger single chunk of data effects pageload. Just as you were concerned about what you thought we introduced with combining fonts.

    Either way glad to see all the discussion.

  25. Franz sounded... April 15th, 2012 at 11:26 am

    @Matti: My primary use for webfonts is site chrome or web app UI, not user-generated content, so the glyph stripping tip was great for me. Especially for HTML5 games and mobile development, where load times are paramount.

  26. Youri notified... May 23rd, 2012 at 2:32 am

    Great article with good research! I was using google fonts quite often, i will have to reconsider that now!

  27. Ross Kendall uttered... October 19th, 2012 at 7:03 am

    Thank you for the very helpful post! Especially liked the tip to use a subset with Font Squirrel expert settings. Using just upper-case made for nice compact font files :-)

Leave a Reply

Please index me, experiment!

“Wait a minute, Mr T.? Are you telling me that you bet on the fight in Rocky III, and that you bet against Rocky?”
“Hindsight is twenty-twenty, my friend.” — Mitch Weaver & Dr. Farthing