Tuesday, 14 May 2013

Addressing CSS2.1/CSS3 @font-face 404s in Internet Explorer

And now for something completely different...

My employer works with several large partners of global brand. Recently, we noted a behavior in Internet Explorer versions 6, 7, and 8--note that we have generally retired support for IE6 and IE7, however a global brand can expose our properties to a large audience that is not technically savvy enough, or cares enough, for lofty principles of supporting core web standards.

The behavior was simply that our Performance Engineering team noted a long term trend of HTTP 404s that periodically spiked with ad campaigns for the brands. The 404s all had GET statements like this:


I saw the problem immeditately: IE was reading @font-face rule declarations past the supported type. Let's look at a typical @font-face rule used1:

@font-face {
  src: url(FQURI/to/eot/font);
  src: url(FQURI/to/woff/font) format('woff'),
       url(FQURI/to/truetype/font) format('truetype'),
       url(FQURI/to/svg/font) format('svg');


One can see where the 404 is being generated. The above rule is documented as the preferred way to load the supporting font files across browsers supporting @font-face rules introduced in CSS2.1. The basic idea is that by loading the IE Embedded OpenType format first, IE will "see it," fetch it, and ignore the rest of the font files and types.

I set to solving the problem. 

First, I installed Windows XP SP3 with IE6 and IE7 in dedicated VMs. Then I created a test page with a typical @font-face rule. Using Fiddler, I was able to track and reproduce the 404 behavior. After reading the CSS3 specification carefully, I started looking for parsing tricks that would halt IE from reading CSS declarations.

I was not finding any. 

So I set to using the specification precisely and found the local(font-name) property of the src declaration would stop IE from continuing to read src declarations:

@font-face {
  src: url(FQURI/to/eot/font);
  src: local(font-name),
       url(FQURI/to/woff/font) format('woff'),
       url(FQURI/to/truetype/font) format('truetype'),
       url(FQURI/to/svg/font) format('svg');

I call this the Irish Local Name Method after Paul Irish who documented this method in 2009-2010, but I didn't discover until last week.2

Editor's Note: It seems that fontsquirrel.com has found a less obtuse hack and is leveraging a more readily readable parsing hack and exploiting an MSDN note on support for the format property in IE8 and less3:

@font-face {
  font-family: 'Slab Bold';
  src: url('fonts/slabbold.eot');
  src: url('fonts/slabbold.eot?#iefix') format('embedded-opentype'),
        url('fonts/slabbold.woff') format('woff'), 
        url('fonts/eslabbold.ttf') format('truetype'), 
        url('fonts/slabbold.svg#Slab-Bold') format('svg');

The use of the format property achieves the same behavior as the use of the local property, but by restating the Embedded OpenType format property that is ignored by IE8 and less.

  1. [1] Brian Hogan in HTML5 and CSS3 recommends this format.

  2. [2] http://www.paulirish.com/2009/bulletproof-font-face-implementation-syntax/

  3. [3] http://msdn.microsoft.com/en-us/library/ie/ms530757(v=vs.85).aspx To specify specific font formats (only for externally referenced font files), use a format hint (format(fontFormat)) where fontFormat is a comma-separated list of format strings that denote supported font formats. Possible fontFormat values are "woff", "truetype", "opentype", and "embedded-opentype". The format hint is optional starting in Internet Explorer 9. (format hints are not supported in Internet Explorer 8 and earlier versions and are ignored.)

Posted by caffeinated at 2:30 PM in 0xDECAF


[Trackback URL for this entry]

Your comment:

(not displayed)

Live Comment Preview:

« May »