Kimler Sidebar Menu

Kimler Adventure Pages: Journal Entries

random top 40

Better @font-face Syntax

Filed in:CSS
Web Dev·The Web

Better @font-face Syntax

September 4th, 2009  · stk

I recently published an article about cross-browser font embedding, using the @font-face CSS selector. It turns out that the code I put forth causes a 404 look-up in Internet Explorer. A reader has suggested some superior code, which I put to the test

Paul Irish Sets My Morning Schedule

Funny how a single comment can change the direction of my day!

Paul proposes two concepts - new to me - in his recent article, "Bulletproof Font Face Implementation":

  • Internet Explorer tries and fails to download the TTF file (with 2-selector syntax) even though the 2nd @font-face selector includes a "format" declaration.
  • He proposes a single @font-face selector, which satisfies all browsers (obviating the need for two selectors), searches the local computer for the font first and eliminates the Internet Explorer "file not found" problem.

Okay ... this is techie, geeky cool and - for sure - not everyone is going to want to read about this, so here is where you should get off the geek train (if you haven't already).

If you're all aboard, heading for geekdom and want to be cool, then read on brave web-font enthusiasts ...

Bringing you up to date

If you haven't heard, since the Jun 30th release of FireFox 3.5 - and for the first time ever on the web - it's possible for cross-browser embedding of fonts. I was one of the first to twig about this and I wrote a *wildly popular* article in early July titled: "xBrowser Fonts" (using fancy embedded fonts, thank you very much)! The article provides a bit of history as well as good resources and a tutorial. You might want to give it a read, if you're new to all this, as today's article is a follow-on.

Today's article is "an exploration", of sorts. Exciting and I'm hoping it pans out, but let's just call it "an exploration", so we don't just run around firing off guns and stuff without checking things.

 

The "Problem"

Because Internet Explorer's support for @font-face is handled differently than the recent CSS3 recommendations, two @font-fact selectors are thought to be necessary. Like this:

Code:

/* for MSIE */  
@font-face {  
  font-family: lexograph;  
  src: url(/fonts/lexograph.eot);  
}  
 
/* for Others */  
@font-face {  
  font-family: lexograph;  
  src: url(/fonts/lexograph.ttf) format("truetype");  
}  
 
/* use the font */  
.lexograph.title {  
  font:2em/1.1em lexograph,verdana,sans-serif;  

 

Having two separate selectors doesn't look as nice as having one, but it just seemed to be the best way to go, at the time. It was my understanding that the reason this worked, was because Internet Explorer couldn't parse the second @font-face selector, because it contained a "format" declaration - it would just ignore it.

Andrea pointed out that Internet Explorer didn't ignore it, but rather, tried to download a very obtuse file instead, which yields a 404 on the server. So, I took a peek at my own server logs this morning, it turns out that Andrea is spot on. Here's a line from our server log, showing what Internet Explorer ends up looking for:

Code:

206.116.133.182 - - [04/Sep/2009:11:42:23 -0400] "GET /fonts/lexograph.ttf)%20format(%22truetype%22 HTTP/1.1" 404 7601 "http://randsco.com/index.php/2009/07/04/p680" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" 

 

Ugly, eh? Well, it's more than ugly, since it's a complete waste of server resources. Looking for a file that we already know isn't there - Bah! It doesn't get much uglier than that. This will not do!

So much for Internet Explorer ignoring that second @font-face selector.

 

Testing Paul's Bulletproof @font-face Syntax

Paul proposes a single selector that not only fixes the "File not Found" issue in Internet Explorer, but also provides (at least for non-IE browsers) the ability to search locally for the font file, before pestering the server to download it. (Actually, it's the "local" declaration that causes Internet Explorer to lose it's head, which means that it truly ignores that line in the CSS, but it's more fun to claim it's a feature than a necessity!)

Here's the code that Paul's suggested:

Code:

@font-face {  
  font-family: "some lexograph";  
  src: url(/fonts/lexograph-paul1.eot);  
  src: local('lexograph'), url(/fonts/lexograph-paul1.ttf) format("truetype");  
}  
 
/* use the font */  
.lexograph.title {  
  font:2em/1.1em "some lexograph",verdana,sans-serif;  

 

So, let's test it. (I modified the font-family name for some later testing, as I want to see if IE loads locally or not. I also modified the EOT filename and the TTF filename, so they'll be easier to pull from the server logs).

Oh ... first I must see if I have the font loaded locally. Yay ... I don't, but the local font is called "Lexographer", not "lexograph", which will be important to know, later. For now I'm just happy it won't find it locally, because I want to test the downloading.

So I hit the page with IE8 and quickly realize - DOH! - while I changed the EOT and TTF filenames in the CSS, I neglected to change them on the server. Ack ... *has to bump everything up a notch to "2"* now! :p

I hit the page again with IE8 and notice the fancy fonts are used on the page (it works for IE) and in the server logs, there's only a call for the EOT file (no 404 for the TTF). Yay! So far, so good.

I'll hit the page with FireFox, Safari and Opera (ewe ... is Opera 10 been released yet? YES! ... upgrade time!) HA ... Opera10 was just released on Sept. 1st and does support the CSS3 font embedding! Yay. Okay ... let me hit it first with Opera .... check the server logs ... should be only one EOT hit and one TTF hit on "paul2" files. Hmmm ... "paul2.ttf" isn't found. Let's try under "paul.html". Hmmm ... I see the Opera hit, but only on the HTML page, no other hits. Odd. Let's try again, with "Paul3" this time. Still nothing. Hmmm, makes me think it's loading it from the local machine, but I don't see how that could be. Even though it's now set to "local('lexographer')" that font is not "loaded" locally (and I can't believe it's pulling it from my HDD location). I changed that name to "lexoman", just to be certain. Delete private data, reload the page, the fancy font loaded (but I notice there's a flash of "normal" font - just like FireFox - before the fancy font is replaces, yuck). Look at the logs again ... finally, there's a "paul3.ttf" 200 entry:

Code:

206.116.133.182 - - [04/Sep/2009:13:52:19 -0400] "GET /test/fontFace/lexograph-paul3.ttf HTTP/1.1" 200 77600 "http://randsco.com/test/fontFace/paul.html" "Opera/9.80 (Windows NT 5.1; U; en) Presto/2.2.15 Version/10.00" 

 

Pauls@font-face bulletproof syntax works!

So Internet Explorer is pulling the EOT (and not looking for the TTF, because it's src first contains a "local()" declaration), as confirmed by the server logs. Additionally, the other browsers (FireFox3.5, winSafari, (presumably macSafari) and now Opera10) all pick up that TTF file. Yay!

 

Testing the Local() Loaded Fonts

I'm curious about the local setting. I'd like to test the other browsers and make sure that there's not a server call if the font is loaded locally. So I'll rename everything EOT, TTF and HTML to "paul4" and see what flies. (Oh, and load the lexographer font locally). Here goes. I'm expecting to see a hit in the log files for paul4.html, but none for paul4.ttf (or paul4.eot), when I load that page - for the first time - using FireFox. (I'll pick on FireFox for a while).

Odd ... no fancy fonts. :(

LOL ... it was the paul.html file I edited "and saved", but it was the paul3.html I renamed to paul4.html. Ack! *renames the saved paul.html file to paul5.html* :p

Disappointing results. Despite having the font locally loaded (not installed mind you, but loaded) and calling it correctly by the name, there's still FireFox still makes a server call for the TTF file:

Code:

206.116.137.182 - - [04/Sep/2009:14:10:24 -0400] "GET /test/fontFace/lexograph-paul5.ttf HTTP/1.1" 200 77600 "http://randsco.com/test/fontFace/paul5.html" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2" 

 

Maybe I'm doing something wrong? Let me install it, just for grins and look at the font information. Maybe it's got a different name? (The font viewer shows - a weird break after the "Jay" - and that the font is called "Lexographer"). Yay, I'm also not breaking any copyright rules, but I already knew that! Thanks Tom Murphy, for making and letting folks use your font, but what's up with the J?

Think maybe the capital "L" might make a difference? Can't imagine. Maybe installation does? Let's try that first. It's installed. *bumps stuff up to 6* and tries with FireFox again. Ewe ... nope, "installation" doesn't make a difference, but the capital "L" does! (Yuck ... the file name has to be exact and capitalization matters! I feel like I'm in grade school all over again).

Now that things are working finally, I'll bump up to "paul8" (I kinda was busy there for a minute) and see if there's any TTF calls in the server logs (I doubt it, but let's be certain). Yep ... no TTF calls, so the browser is grabbing the local (installed) version. Crap, suppose now I need to test a loaded (not installed) font. Eye Veh! *bumps up to paul9* Yeah, worked fine (it picked up the loaded font, even when I renamed the font files to something that doesn't exist).

Now, for the final, fancy test. Will Internet Explorer pick up the font file locally, if I just specify it when I use it, saving a EOT download (I kinda doubt it, since the @font-face selector comes first). Here's what I mean:

Code:

@font-face {  
  font-family: "some lexograph";  
  /* even though we know IE will pick up the red line */  
  src: url(/test/fontFace/lexograph-paulx.eot);  
  src: local('Lexographer'), url(/test/fontFace/lexograph-paulx.ttf) format("truetype");  
}  
 
/* now use the fonts like any other font */  
.lexograph.title {  
  /* will it load the local file instead? */  
  font:2em/1.1em Lexographer,"some lexograph",verdana,sans-serif;  

 

I went to "paulx" here, cause - hopefully - it's my last test (whew!)

The answer, as I expected, is "No". IE will load the EOT file, even if it's locally loaded and named correctly when you use it, later on.

Code:

206.116.133.182 - - [04/Sep/2009:14:38:56 -0400] "GET /test/fontFace/lexograph-paulx.eot HTTP/1.1" 200 39500 "http://randsco.com/test/fontFace/paulx.html" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" 

 

This concludes today's testing. Hasn't it been fun?

ACK! I forgot all about my font-family test. I set it up at the very beginning and forgot all about it, when I renamed the font-family to "some lexograph", rather than give it its true name, which turns out to be "Lexographer". Let's go back and try a "paulz" case, using that. (Here's what I want to test, to see if IE skips the EOT file GET)

Code:

@font-face {  
  /* will IE load locally and skip the EOT GET? */  
  font-family: "Lexographer";  
  src: url(/test/fontFace/lexograph-paulz.eot);  
  src: local('Lexographer'), url(/test/fontFace/lexograph-paulz.ttf) format("truetype");  
}  
 
/* now use the fonts like any other font */  
.lexograph.title {  
  font:2em/1.1em Lexographer,verdana,sans-serif;  

 

Well, isn't that a kick in the pants. Internet Explorer downloads the EOT file, even though the real font file (named in the font-family declaration) is loaded on the local computer.

Code:

206.116.137.182 - - [04/Sep/2009:15:06:44 -0400] "GET /test/fontFace/lexograph-paulz.eot HTTP/1.1" 200 39500 "http://randsco.com/test/fontFace/paulz.html" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" 

 

In a very round-a-bout way, maybe this makes sense, as the (precious little) information on Embedding Font on the Microsoft Developer Network indicates: "... however, Internet Explorer 4.0 downloads, decompresses, and temporarily installs font objects, even if the real font is present on the user's computer." (source)

Conclusions

As Andrea points out, using two @font-face selectors leads to unnecessary work for the server, as Internet Explorer will look for munged TTF font file. Paul introduced some bullet-proof @font-face syntax that fixes this and affords other browsers the opportunity to load the file locally, before downloading the TTF or OTF font file off the server. My personal testing verifies that Paul's method is indeed superior. Also, there appears to be no point of trying to tell Internet Explorer "look for this font locally", because IE is just plain stubborn and will download the EOT regardless.

My hat is off to both Andrea and Paul! Thanks for turning me on to this superior method and I'll be amending (and crediting) the copy in my xBrowser Fonts article.

Cheers!

Legal Disclaimer: All the tests performed during the construction of this article were performed by yours unruly, even the botched ones. No animals were harmed or used during this testing, only electrons were pushed around and even those, weren't pushed very far. Server logs are real, though the IP address was modified, so that some other Canadian can be blamed ... and to protect lil'ol innocent me. Too much coffee was probably consumed, during the making of the this article (which explains all the flushing sounds). However, since the outcome was positive, this is fully and completely justified. If you've read this far, congratulations. I'd give you a prize, but as a certain Yabba can attest, it'd probably take me over 6 months for me to get it in the post, so you're better off just patting yourself on the back. Have a great day!
(Permalink)
Views: 51510 views
10 Comments · GuestBook
default pin-it button
Updated: 23-Aug-2010
Web View Count: 51510 viewsLast Web Update: 23-Aug-2010

Your Two Sense:

XHTML tags allowed. URLs & such will be converted to links.


Subscribe to Comments

Auto convert line breaks to <br />

1.flag elliottcable Comment
09/04/09
I don’t know what you’re smoking, but “ If you haven't heard, since the Jun 30th release of FireFox 3.5 - and for the first time ever on the web - it's possible for cross-browser embedding of fonts.” is completely off. WebKit’s supported that, and I’ve been using it, forever.

Nobody cares about FireFox anymore, switch to a WebKit browser already… FireFox is the new IE.
2.flag John Comment
09/04/09

Nobody cares about FireFox anymore


Um... I don't know what your smoking either Elliot however I look forward your supporting data for that word "nobody".

@Scott, thanks for the additional effort.
Signed - "nobody"
3.flag stk Comment
09/04/09
@Elliottcable - Chrome, which is a WebKit browser, doesn't support @font-face out of the box.

"Nobody cares about FireFox" is laughable, since more than 26,000 of our Jun09 visitors use it! (Your definition of "nobody" is nearly as accurate as your definition of "forever".) :p

I smoke reach. Prior to Jun 30th, @font-face was supported by only 72% of our visitor's web browsers. After Jun 30th, that percentage rose to just over 97%. That's cross browser to me (and why the statement is spot on).

Keep puffing funny definitions though. :D

@John - No worries. Just crossed my desk this morning and peaked my interest. (Yanks, eh? :p)

4.flag Richard Fink Comment
09/11/09
In my tests, it seems Opera is choking on Paul's interOPERAble solution.
5.flag Carl Johan Comment
09/11/09
Sweet, I've been wanting to do something about that crap turning up in my weblogs :)
6.flag stk Comment
09/11/09
@Richard - After you commented, I went to test my version of Opera 10. Seems it's picky about the  local() syntax.

(i.e.,  local(font), fails, but  local('font'), and  local("font"), both work)

This article (and test page) work fine for me.

@Carl - Glad to have helped clean your logs!
7.flag Landon Comment
10/27/09
@Elliottcable According to W3 as of September 2009 about 46% of "nobody" uses Firefox. Webkit browsers? around 12%.

Good post!
8.flag stk Comment
10/27/09
@Landon - Hello Peru! (Thanks)
9.flag simonjs Comment
11/05/09
One thing to note here is to make sure you have the correct name for the font that is stored locally when using mutiple weights:


@font-face {
font-family: "FontName";
src: url("/fonts/FontName.eot");
src: local("FontName"), url("/fonts/FontName.ttf") format("truetype");
}

/* differentiated from */

@font-face {
font-family: "FontName";
font-weight: bold;
src: url("/fonts/FontName_bold.eot");
src: local("FontName Bold"), url("/fonts/FontName_bold.ttf") format("truetype");
}

.myfont {
font-family: "FontName";
}

.myfont-bold {
font-family: "FontName";
font-weight: bold;
}
10.flag EdB Comment
05/18/10
Awesome. I kinda figured if I bookmarked this I'd one day want to try to figure it out so I did and I did and it works. But you knew that. The part about 'it works' I mean. You knew it worked. What you didn't know was that even someone like me could copy/paste and get 'er done.

Wouldn't it be way cool if maybe there was an open source blog engine that took full advantage of this and took the time to include several ... what would you call them? templates? Okay several templates that included ttf and eot files of fonts that are totally cool to use in this manner instead of the possibly inappropriately used font that someone (other than me - of course) might have tinkered with?

Not sure when I'll make a public spectacle of the domain using this, but one day it'll happen.

Thanks!