Optimizing @font-face For Performance

You want to use @font-face, then you realize it’s got some downsides. First of all, it’s another http request, and we know that the golden rule of web performance is to keep http requests to a minimum. Secondly fonts aren’t even small files, they can be 50k+ in size. Lastly the lag of fonts loading last means you page seems to morph into it’s final form.

Here’s a cool little optimization. By using a data: url you can use the font inline by encoding in base64. For example:

@font-face {
    font-family: "My Font";
    src: url("data:font/opentype;base64,[base-encoded font here]");
}
 
body {
    font-family: "My Font", serif
}

You can see this in action here. This seems to work fine in Firefox 3.5, and Safari 4 (presumably any modern WebKit based browser). Other browsers will simply act as if they don’t support @font-face.

In practice I’d recommend putting it in a separate stylesheet rather than inline css so that your pages are smaller and css can be cached for subsequent page views.

Data url’s are part of Acid2, which most modern browsers either pass or plan to pass. If you use an Open Type font you’d get pretty decent compatibility (IE only supports Open Type). Using True Type you’d still get pretty good compatibility sans IE. Check the @font-face page on MDC for more details. Unlike images, browsers that support @font-face are likely to support data: url’s as well, making this a pretty good solution.

Special thanks to Open Font Library for having some nice free fonts with awesome licensing. This post was partially in response to a comment left the other day on my @font-face hacks blog post.

17 thoughts on “Optimizing @font-face For Performance

  1. The base64 encoding used in the data: uri will increase the font’s size by a third. Gzipping the css file probably reduces this to something lower, but not to a factor of one. So if file size matters, it’s probably better to leave the font a separate file. After the first page load, (in a proper setup) it will be cached just like the css.

    Also, the whole page won’t be shown until *all* css files have downloaded completely. So while this technique prevents some text from showing up in a “wrong” font for a short while, it prevents the whole page from showing up at all for that same time.

  2. Very true.. but most sites gzip these days cutting down the file size… I suspect you’d see 10-15% overhead in practice.

    Considering the large amounts of JS and images on many sites today and the proliferation of broadband connections, file size is generally less important than the # of requests.

    A typical cable modem connection these days can easily handle 6Mbps and burst as high as 20Mbps. Unfortunately the latency is still there.

    An extra 30kb (assuming 2x 15kb overhead on a base64′d 50kb font) is going to be perceived faster in many cases than an 2 extra requests (assuming you only use 1 serif and 1 sans serif font). Especially if your not offloading to a CDN or other low latency origin.

  3. This “good advice? will be spotted by copyright-fanatics to enweighten their websites in 3…. 2…. 1….
    Oooooooh ! JPEG headers and backgrounds urldata-encoded in the source code !

    Just joking. Anyway, it is very useful, if you use this kind of technique (and it’s better for very small documents, as 1Kb png images, not for 50Kb fonts), to activate gzip compression on server-side. But remember that CSS and JS zipped-served are NOT cached by MS-W-IE. So, use it a lot, it makes a better “cool and fast attitude? for non Trident based modern navigators ;)

  4. @James John Malcolm: Yes, but in practice the latency of several fonts will likely be more of a performance barrier than a few extra KB.

  5. A separate stylesheet is no better than a separate font file.

    In fact, if both are external, I won’t bet (without pre-testing) on whether the Access Control headers fail for the former.

  6. Are fonts really cashed? I still get the effect of seing the text shown for a milisecond without the downloaded font when refreshing a page that downloads a font.

    This effect is quite ugly, I don’t see this with Safari 4

  7. But, if you could use localStorage that is new in FF3.5 then the font would ONLY be downloaded 1 time.
    The only catch is how to get the data:url string from localStorage and into @font-face src?

  8. @Robert Quite right, that’s one of the reasons I’m happy FF3.5 shows you the text in non-@font-face fonts first.

    Also, Typekit is supposed to break up the font files in different bits (as part of their drm font-protection) which would add extra latency…

  9. Pingback: samgrantdesign » Blog Archive » Using the @font-face tag

  10. Pingback: Font Dragr: A drag and drop font tester | The CSS Ninja - All things CSS, Javascript & xhtml

  11. Great little article thanks, I used it on my site just now and no-longer get the whole site in serif then a split second later turning into nice font, just loads straight into museo :)

  12. Pingback: CSS Data URIs – Use Them In All Browsers Now! | Jon Raasch's Blog

  13. Pingback: Banner-style Animation with GreenSock-powered JavaScript

  14. Pingback: CSS Data URIs With Cross Browsers « blog.topwebdevelop.com

  15. Use base64 encoded font and then serve @font-face .otf files to IE only using comments. This avoids the Flash Of Un-styled Text issues and is extremely fast.

Leave a Reply

Your email address will not be published. Required fields are marked *

Connect with Facebook

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>