This week, my colleague and I achieved what we thought was impossible: FOUT-less custom fonts, in pure CSS. You noticed it on this site, and would have seen it a few minutes ago, when you were checking out Raptor Editor. How did we do it?

Data URI those bad-boys

Update: as passcod commented, this isn’t a new idea, and there are trade-offs to consider.

As always, our first consideration was IE7. Not really, but it is important to consider browsers with limited data-uri support. For IE7, one must first include the EOT & SVG files normally, and the woff & ttf fonts with data-uri urls in a separate font-face declaration after that. I’ve included an example below.

This snippet is an extract from the comprehensive gist that my colleague created – embedded fonts. It includes a demonstrations of how to achieve this with Compass.

Why not just use Typekit?

Until very recently, we used Typekit non-web safe fonts on our sites. We loved it. Custom fonts for all, with no FOUT in sight.

We decided that we would have to stop using the service after we noticed that Typekit would occasionally cause page to loads pause for extended periods or timeout completely. These issues were caused by the way Typekit works, blocking page rendering while it loads in the required fonts.

If the Typekit server is slow or unavailable, it will appear to the user that there is an issue with the website, and in extreme cases are not able to use the site at all. These issues are what prompted us to investigate alternative ways to use custom fonts without a FOUT.

What about you?

I’m interested to know what you think of this method – have you used it or something similar before?

Trade offs

passcod raised some issues with the approach suggested here. They are important, so I’ve updated the post to include them below.

No more caching for woff and truetype!

You’re embedding the same font twice in two formats

The reason these issues are worth mentioning is that they result in an increased file size.

For me, this increased file size is a bearable price to pay to remove FOUT, especially considering that the CSS file itself will be cached. Yes, the initial download will take longer, but won’t happen with each page load.

– No more caching for woff and truetype!
– You’re embedding the same font TWICE in two formats…
– and all that causes a massive increase in file size.

For those reasons, I generally try to keep away from data-uri embedding, esp. in situations that require duplicate content. The only time I ever used it completely intentionally was because I was constrained to a single file…

As for FOUT… well, you are indeed avoiding it for those browsers that support data-uris, but only because the CSS loading sequence goes thus:

Now, a bit of a conjecture: you could possibly modify the sequence somewhat by preloading the fonts before the CSS. This doesn’t necessarily require JavaScript, either: if you’re okay with having a few errors in the console, you can use tags to load those files in the head, before the that’d load your css. Note that modern browsers do try to load stuff async’ly, so that may cancel itself :( With proper testing, though, it might be worth a shot.

You raise valid and interesting points, and I agree, this isn’t a new idea. I should have been clear about that in my original post!

Those are significant trade-offs. FOUT is a real issue for us, so we don’t mind bearing the cost of larger CSS files (with duplicated content). Other developers might feel differently, so I’ve included your caveat in the post.

If I get a chance, I will try your suggested alternative – if you get to it before me, please let me know?

Recent Posts

Meta Mate 1.1.14 is ready for you! This version ensures compatibility with RapidWeaver 6. RapidWeaver 5.4 users please note - you may have to manually upgrade from Meta Mate 1.1.13. To do this, open Finder, press Command+Shift+G, and type ~/Library/Application Support/RapidWeaver. Drop the unzipped plugin…

Inheriting a codebase isn't fun. Even less fun if the code is filled with so many memory leaks that the only solution is to force a full page load on every route change. Below is a solution that works well in modern browsers, and IE9.…