Mo’ Bulletproofer @Font-Face CSS Syntax

Sep 15, 2009

[3-28-10] Where @Font-Face Is Today

Now that web fonts are supported in Firefox 3.5 and 3.6, Internet Explorer, Safari, Opera 10.5, and Chrome, web authors face new questions: How do these implementations differ? What CSS techniques will accommodate all?

Firefox developer John Daggett recently posted a little roundup about these issues and the workarounds that are being explored.
In response to that post, and in response to, particularly, Paul Irish’s work, I came up with the following @font-face CSS syntax. It’s been tested in all of the above named browsers including IE 8, 7, and 6. So far, so good.

The following is a test page that declares the free Droid font as a complete font-family with Regular, Italic, Bold, and Bold Italic. View source for details.

Alert: Be aware that Readable Web has released it’s first @font-face related software utility for creating natively compressed EOT files quickly and easily. It has it’s own web site and, in addition to the utility itself, the download package contains helpful documentation, a test font, and an EOT test page. It’s called EOTFAST If you’re working with @font-face, it’s a must-have.

Here’s The Mo’ Bulletproofer Code:

@font-face{ /* for IE */
@font-face { /* for non-IE */
src:url(http://:/) format("No-IE-404"),url(fishy.ttf) format("truetype");

The above code solves the two biggest one big problem I found in my own testing. See “Solving A Problem With IE 6, 7, and 8” down below.

  1. [Update:] As of Opera 10.5, Opera has very full-featured @font-face support. Synthesized bolding and italic still don’t work as of 10.51, but the developers are working on it and it should arrive soon.
    Therefore, the following harsh information is now, happily, obsolete and I can now travel to Norway in safety.
    The following won’t work in Opera 10:

    @font-face {
    font-family: FishyFont;
    src: url(fishy.eot); /* for IE */
    src: local(FishyFont), url(fishy.ttf) format("truetype"); /* for non-IE */

    Opera will not accept an @font-face rule containing a src target with an EOT extension. This is apparently by design. I believe the standards-compliant approach is for the browser to ignore a rule it doesn’t un­der­stand and move on to the next. (But in Opera it seems that defeating EOT is a higher priority, lending credence to Joe Clark’s recent assertion that Opera 10 just plain sucks.)

Solving A Problem With IE 6, 7, and 8

In an @font-face rule containing a font file extension that IE doesn’t support – TTF/OTF – or format hints – format("truetype") – that IE can’t understand, IE still attempts to resolve, as a URI, the text contained within the first and last parens following “src:”.
In other words, IE makes a HTTP call in an attempt to access a resource that doesn’t exist. And then waits for the server to respond, which it does, with a 404. This is a performance problem. (And a hidden one, at that – only revealed by using special tools, like Fiddler2, with which you can track and analyze HTTP traffic in and out of the browser.)

I have no problem with the redundancy of having two @font-face rules: one backward compatible for IE 6,7,8 and one forward compatible for the others and IE-Next. I prefer NOT co-mingling the standards compliant declarations with the backwards-compatible declarations and think it will be a far less confusing, and more debuggable approach in the long run – especially in a complicated page with several fonts and weights in play. So all of this is fine by me – as I see it, it’s CSS that more accurately maps to the different implementations, file formats, and rendering engines involved.

Provided this syntax survives hard and extensive testing – which it shoulddoes, it’s pretty simple – the only con that I can see is some extra bytes in the style sheet.
It makes Opera happy, keeps the @font-face rules separate without relying on conditional comments, avoids the additional HTTP request(s) by IE, and leaves local() as an option, not a requirement.

As an addendum, here’s a copy of my full reply on the W3C mailing list, with an analysis of Paul’s syntax and my reasons for looking to do it another way.

Alert: The following is now obsolete, as well. As of mid-december 2009, Chrome’s standard build features @font-face support without any special enabling.

Note: Currently, Chrome has web fonts off by default, you have to launch chrome.exe with the “–enable-remote-fonts” parameter to enable it. Tip: Use the latest version, too. [12-21-09] Update: The new Chrome Beta no longer requires using the –enable-remote-fonts command line switch. See:@Font-Face Works Automatically In New Google Chrome Beta

(And a special thanks to Ali G for the headline. Glad I axed.)

Update [09-16-09] Re: Paul Irish’s Syntax Using local To Hide Stuff From IE

After considerable back-and-forth between Paul Irish, Scott Kimler, and myself, we’ve seen test pages using the local descriptor that work in Opera, and some that don’t. Error messages vary. In one case, the EOT file is reported as an “invalid src property”. In another, an unquoted font name in the local descriptor is reported as a “declaration syntax error”. And in another, my personal favorite, it reports “web font discarded – malformed” for the EOT.
What we have here seems like a buggy implementation. (My tests reveal other inconsistencies between Opera and Webkit/Firefox, as well. Stay tuned.) Opera is marginal and bugs will, presumably, be fixed. Paul Irish’s solution is a one way to go but with care and awareness of potential pitfalls. (See note in next paragraph: 12-2-09.)
As always, test, test, test.

Update [12-02-09] Re: Font Names And Using The Local() Descriptor

The local() descriptor was deliberately left optional in CSS3. Following up on any potential downsides to using the local() descriptor to specify a name for a font already installed on the local operating system, there is a thread on Typophile about possible problems that might arise. Different Fonts Named The Same: Does This Happen Frequently? Note [12-21-09]: After careful consideration, research, and discussion – I strongly recommend that you don’t use local() at all – except in special situations. Such as when the size of the font is so large that the opportunity to speed up rendering outweighs the risk that the font installed in the local Operating System may be different than the one on your server. Choose wisely. There will be more about this here and elsewhere, soon.

Sharing Options:

Leave a Comment

Previous post:

Next post: