F Blog Home
February 3, 2011
Updated: April 21, 2011 10:49 AM EST
Since the beginning of the 'webfont revolution' we've relied on somewhat hacky @font-face declarations to get webfonts loading cross-browser. Could there be a better way? One that's clear and compatible with future browsers?
In September 2009, Paul Irish came up with the Bulletproof syntax for writing the @font-face declaration. It was compact and worked across all browsers at the time. Recent, growing complaints that fonts weren't loading in Android, led me to recommended the Mo' Bulletproofer syntax devised by Richard Fink instead. Unfortunately Mo' Bulletproofer requires double declarations. Defining each font twice in the CSS is cumbersome, so I looked for a better solution.
The code should have been clean, clear and simple all along. Finally, it is:
@font-face { font-family: 'MyFontFamily'; src: url('myfont-webfont.eot?#iefix') format('embedded-opentype'), url('myfont-webfont.woff') format('woff'), url('myfont-webfont.ttf') format('truetype'), url('myfont-webfont.svg#svgFontName') format('svg'); }
The hack trick that makes this work is the '?' following the EOT filename. Seriously.
Internet Explorer <9 has a bug in the parser for the src attribute. If you include more than one font format in the src, IE fails to load it and reports a 404 error. The reason is that IE attempts to load as a file everything between the opening parenthesis all the way to the very last closing parenthesis. To deal with that wrong behavior, you merely declare the EOT first and append a single question mark. The question mark fools IE into thinking the rest of the string is a query string and loads just the EOT file. The other browsers follow the spec and select the format they need based on the src cascade and the format hint.
Safari 5.03, IE 6-9, Firefox 3.6-4, Chrome 8, iOS 3.2-4.2, Android 2.2-2.3, Opera 11
You can use this syntax as well to embed your fonts into a stylesheet. For it to work does require two declarations however. But if you are going this route, what is an extra declaration? Note that the format hint for the EOT needs to be 'embedded-opentype.'
@font-face { font-family: 'MyFontFamily'; src: url('myfont-webfont.eot?') format('embedded-opentype'); } @font-face { font-family: 'MyFontFamily'; url(data:font/truetype;charset=utf-8;base64,BASE64_ENCODED_DATA_HERE) format('truetype'), url(data:font/woff;charset=utf-8;base64,BASE64_ENCODED_DATA_HERE) format('woff'), url('myfont-webfont.svg#svgFontName') format('svg'); }
Albert Ward offered to translate this post to Bulgarian
The CSSNinja made a great observation about how to get IE9 to take a WOFF instead of the EOT. He suggested adding a hash to the format hint of the EOT. This works because IE9 doesn't recognize the format hint '#embedded-opentype.' So I modified the syntax to reflect his finding. I changed the format hint from 'embedded-opentype' to 'eot' which IE9 doesn't understand either and therefore moves on to the WOFF. We've reverted back to the correct format hint for eot, format('embedded-opentype') due to issues with serving on IIS. See this post for details.
IE was failing to load webfonts if the page was loaded locally. Turns out that IE prefers the '?' question mark character. The code has been updated to reflect this. Originally this post lauded the magical '#' hash. Hat tip to Chris Neale for the idea.
In response to this syntax not working in IE9 Compatibility modes (as well as an extended conversation with Microsoft) we've updated the syntax slightly. The revision adds redundancy, but further bulletproofs the method. Please see our separate post about this here.
When this syntax is used on an IIS server, IE9 users may not see the font. This can be solved in two ways. 1) Add the WOFF format to the list of MIME types. or 2) change the format('eot') portion to format('embedded-opentype'). Either one will solve issues with IE9.
Andrew Staffell
February 3, 2011 at 12:33 PM
Richard Fink
February 3, 2011 at 12:34 PM
Tom
February 3, 2011 at 12:34 PM
Erik Vorhes
February 3, 2011 at 12:36 PM
Derek
February 3, 2011 at 12:41 PM
Paul Irish
February 3, 2011 at 12:41 PM
Joen
February 3, 2011 at 12:49 PM
Niki Brown
February 3, 2011 at 01:03 PM
Christopher Beckwith
February 3, 2011 at 01:11 PM
Spencer
February 3, 2011 at 01:25 PM
Peter Gasston
February 3, 2011 at 01:26 PM
Ethan Dunham
February 3, 2011 at 01:31 PM
Jonathan Snook
February 3, 2011 at 01:45 PM
Stephanie (Sullivan) Rewis
February 3, 2011 at 01:54 PM
Marius Ciobotaru
February 3, 2011 at 01:57 PM
Raphael Essoo-Snowdon
February 3, 2011 at 02:03 PM
Jason Cranford Teague
February 3, 2011 at 02:07 PM
Ethan Dunham
February 3, 2011 at 02:08 PM
Agos
February 3, 2011 at 02:10 PM
Jean-Philippe Sirois
February 3, 2011 at 02:15 PM
Richard Fink
February 3, 2011 at 02:18 PM
Denise Jacobs
February 3, 2011 at 02:26 PM
Matt Wiebe
February 3, 2011 at 02:27 PM
NetRoY
February 3, 2011 at 02:32 PM
Zoltan Hawryluk
February 3, 2011 at 02:35 PM
Ethan Dunham
February 3, 2011 at 02:38 PM
Leads
February 3, 2011 at 02:40 PM
Thijs van der Vossen
February 3, 2011 at 03:02 PM
Ryan Corradini
February 3, 2011 at 03:03 PM
Wilkins
February 3, 2011 at 03:19 PM
chapolito
February 3, 2011 at 03:19 PM
Stephanie (Sullivan) Rewis
February 3, 2011 at 03:30 PM
Erica J
February 3, 2011 at 03:45 PM
Brian Klepper
February 3, 2011 at 03:58 PM
Batfan
February 3, 2011 at 04:04 PM
Andreas Papula
February 3, 2011 at 04:09 PM
karl
February 3, 2011 at 04:11 PM
darcy
February 3, 2011 at 04:15 PM
admazy
February 3, 2011 at 04:18 PM
Ethan Dunham
February 3, 2011 at 04:24 PM
Kirk Franklin
February 3, 2011 at 04:34 PM
darcy
February 3, 2011 at 04:34 PM
Ethan Dunham
February 3, 2011 at 04:42 PM
Geoff
February 3, 2011 at 04:52 PM
Paul Irish
February 3, 2011 at 05:17 PM
Chris
February 3, 2011 at 05:20 PM
Kirk Franklin
February 3, 2011 at 05:58 PM