Archive

Archive for the ‘front-end development’ Category

Introducing… CSS3Please.com

March 9th, 2010

Man, whenever I'm writing some css3, I get so tired of writing all the vendor-specific prefixes (like -moz-border-radius). Combo that with remembering who supports what and I wantedneeded a shortcut.

Today, I'm happy to release v1.0 of css3please.com: a cross-browser css3 rule generator, produced by Jonathan Neal and myself. In addition to syncing and normalizing changes across the necessary properties, it also sneaks in IE support for a few features via IE filters. Right now it helps you write the rules for: border-radius, box-shadow, linear-gradients, rotation and @font-face. A few more transforms like skew and scale are on their way, stay tuned.

Shouts to all the good people doing research and making tools in the css3 arena: John Allsopp, Chris Coyier, Stoyan Stefanov, Damian Galarza, Ryan Seddon, border-radius.com.

Please leave comments and feedback below.

Paul Irish front-end development

Front-end development feeds to follow

March 1st, 2010

If you're running low on front-end oriented stuff to read, I've got 130 feeds of high quality for ya.

Here is the OPML file: frontendfeeds.xml

You can add these to your Google Reader via Settings (in top right), then Import, then upload file.

If you want a peek, a preview via opmlviewer.com.

Paul Irish front-end development

Memorable hex colors

December 4th, 2009

Hopefully this will save you a trip back to Photoshop's color picker.

  • #b00b00
  • #de1e7e
  • #e1e100
  • #BADA55
  • #F0FEAF
  • #ac1d1c
  • #facade

These ones are memorable, but not terribly color-appropriate:

  • #c0ffee
  • #defec8
  • #deface
  • #0ff1ce
  • #a55

Thx for the awesome suggestions: @mrspeaker, @8centsaday, @wilto, @lrbabe, @twalve
If you have any good ones to add, holler in the comments!

I guess I have a thing for hex colors.. ;)

Paul Irish front-end development

Fighting the @font-face FOUT - Quicken the load time

October 7th, 2009

FOUT is what I'm calling the flash of unstyled text that you get while using @font-face in Firefox and Opera.

In June, Remy Sharp documented the how a browser progressively renders a page using @font-face. Things work differently between browsers natch:

Here's how in Firefox; basically the text is in a default webfont until the custom font is ready:

Webkit takes a very different approach, and very intentionally. They believe it's better to keep the text invisible until the font is ready. This way, there is no moment where the text flashes into its newly upgraded self. (This moment should be familiar to you if you've used sIFR)

I really don't like the text upgrade FOUT, so I personally prefer webkit's technique. But either way, we want the font loaded ASAP, so let's speed it up!

Best practices for serving fonts:

  • Minimize the overall kilobyte size of your font file. You can reduce the size of your font file by subsetting it (more on this later).
  • Heavy caching via a far-future expires header.
  • Gzip? Well, no; you can't gzip a font file, though you can gzip a css file that holds the data-uri representation, but you don't get much gain there. It'd primarily be an obfuscation technique.Stoyan Stefanov has done some excellent research into @font-face and gzip. Summary: It's possible! 40-45% savings. Do It!

When exactly do browsers download the font file?

Garrick at Kernest tipped me off to IE's interesting behavior here.

After some research we can see when the asset download is initiated:

  • IE will download the .eot file immediately when it encounters the @font-face declaration.
  • No browsers download the font file when they find a css rule that references the @font-face font.
  • Gecko, Webkit, and Opera all wait until they encounter HTML that matches a CSS rule with a fontstack including the @font-face font.

I've put up a test page where you can experiment and watch your dev tools to see when the file is grabbed.

In what cases will you get a FOUT
  • Will: Downloading and displaying a remote ttf/otf/woff
  • Will: Displaying a cached ttf/otf/woff
  • Will: Downloading and displaying a data-uri ttf/otf/woff
  • Will: Displaying a cached data-uri ttf/otf/woff
  • Will not: Displaying a font that is already installed and named in your traditional font stack
  • Will not: Displaying a font that is installed and named using the local() location

Let's get the font ASAP

The sooner the better, so let's prioritize getting this font before everything else.

We'll set up our @font-face declaration:

    /* chunk will load immediately in IE at this declaration*/
    @font-face {
    	font-family: 'ChunkFive Regular';
    	src: url('fonts/Chunkfive.eot');
    	src: local('ChunkFive Regular'), local('ChunkFive-Regular'), url('fonts/Chunkfive.otf') format('opentype');
    }
    /* define a class that uses this font */
    .chunk { font-family:'ChunkFive Regular'}

And inside the <head>, we'll include this:

(function(className){
    // quit early if we're in IE, no need to do any of this.
    if (/*@cc_on!@*/0) return;
 
    var f = document.createElement('fontdl');
    f.innerHTML = 'fontdl';
    // associate with the @font-face declaration and hide it
    f.className = className;
    f.style.cssText = 'position:absolute; visibility:hidden'
    // it's still off-DOM so it doesn't download yet
 
    // document.body doesnt exist yet so we'll add it onto the HTML tag
    document.documentElement.appendChild(f);
    // font download initiated Now.
    // let's clean up after ourselves (opera needs a timeout > 0)
    setTimeout(function(){f.parentNode && f.parentNode.removeChild(f)},100)  
})('chunk'); // <== pass in the class here.
2009.10.10: Based on a tip from my colleague Adam McIntyre, we have a more elegant solution than the above javascript. It, along with more fontstack research, is as follows…

Rather than creating an element on the fly that uses the font, we do the same with HTML:
Adam postulated the we could do the same trick by classing the HTML tag:
(e.g. <html class="chunk">)

  • The font-family style won't actually cascade, so no worries about it being inherited by your content
  • This works in Gecko and Opera, but not Webkit

Alternatively, we add an applicable element to the head:
<b class="chunk" style="position:absolute; visibility:hidden">download please</b>

  • Works in webkit, gecko, opera. Waa hoo!
  • Obviously this doesn't validate. FYI, The element will be thrown into the <body> on page load.

Can I pre-load all the font assets?

So let's say we have more than one @font-face declaration:

@font-face { font-family: 'ChunkFive Regular'; src: local('ChunkFive Regular'), url('fonts/Chunkfive.otf') format('opentype'); }
 
@font-face { font-family: 'League Gothic'; src: local('league gothic'), url('fonts/LeagueGothic.otf') format('opentype'); }

If we set a new class that references both new fonts in a single fontstack, and then pass use that class for our above techniques:

  • Gecko retrieves all webfonts mentioned in the font stack.
  • Opera retrieves all webfonts mentioned in the font stack.
  • IE, as mentioned, retrieves them when they're declared, not used.
  • Webkit retrieves each font mentioned sequentially until it finds a working one.
    • 404s and invalid files are considered non-working, of couse.

So with some CSS like so:

    .chunk { font-family:'ChunkFive Regular'}
    .league { font-family:'League Gothic'}
    .allfonts { font-family: 'ChunkFive Regular', 'League Gothic'; }
<!-- preloads both fonts in gecko and opera, webkit only gets the first -->
<b class="allfonts" style="position:absolute; visibility:hidden">download please</b>
 
<!-- preloads all the fonts in the fontstack in gecko, opera, and webkit -->
<b class="chunk" style="position:absolute; visibility:hidden">download please</b>
<b class="league" style="position:absolute; visibility:hidden">download please</b>

Is this the end-all be-all solution to quick load and FOUT?

Nope. As Jonathan Snook pointed out in the comments, these won't elimate seeing the fallback font FOUT in Gecko and Opera, they only prioritize the load of those fonts. As we know, browsers have a limit of concurrent connections, so we're using these tricks to get the fonts first in line.

Also, This is really only for the initial time, because after that, your far-futures expire header means the ttf stays cached locally, no more requests needed.

I'm not sure if we'll be able to use webkit's transparent font load in Gecko in any graceful way. (It's possible with a sniff and polling, but that seems like overkill) I'm also not sure if we'll get Gecko's load technique in Webkit, which would be optimal for slow/mobile connections. For the time being your time is best served getting the font size very small, gzipping it, prioritizing it first, and caching it for a while.

Defeat the Firefox FOUT entirely

A little bit ago, Typotheque posted a technique aiming to avoid the FOUT. Using jQuery, they hide the body on dom ready, and then reveal it at the window load event.

The posted technique doesn't work as:

  • It targets all users, but we should only tweaks things for Firefox 3.5+ users.
  • Users will actually see the text before it's hidden during at dom ready.
  • As was mentioned earlier, fonts are downloaded when text appears in the page that the font will apply to. Therefore, anything hidden with display:none will not request the font file.
  • Not everyone has jQuery, so let's go with something more general

The one serious caveat to this technique is: The page will not be visible until all content, iframes, remote scripts, fonts, and images are downloaded. for a maximum of three seconds (I added a three second bailout condition, read below.)

This should run in the <head> somwhere:

(function(){
  // if firefox 3.5+, hide content till load (or 3 seconds) to prevent FOUT
  var d = document, e = d.documentElement, s = d.createElement('style');
  if (e.style.MozTransform === ''){ // gecko 1.9.1 inference
    s.textContent = 'body{visibility:hidden}';
    e.firstChild.appendChild(s);
    function f(){ s.parentNode && s.parentNode.removeChild(s); }
    addEventListener('load',f,false);
    setTimeout(f,3000); 
  }
})();

First, we are detecting if we're firefox 3.5+ by seeing if -moz-transform is supported, which was added at the same time. We use visibility:hidden instead of display:none, so that the font will actually be requested, and we remove that style once the page has finished loading. We're hinging on window load to be our re-entry point, because as Steve Souders pointed out, "font files block the window’s onload event from firing in IE and Firefox, but not Safari nor Chrome."

I've also added a 3 second bailout condition; this means if the page has not completely loaded in three seconds, we're going to show it anyway. It's possible the font won't be ready, but unlikely, I believe. This aims to solve the issue Remy found with the Standards.next site. I wouldn't recommend it, but you can disable this behavior by commenting out the setTimeout line.

2009.11.07. Added the Defeat the Firefox FOUT section.

2009.11.08. Tweaked defeat FOUT code to have a 3 second bailout.

2009.12.14. Added the In what cases will you get a FOUT section.

Paul Irish front-end development, typography

Chrome and @font-face: It's here!

September 25th, 2009
January 25, 2010: It is now in the stable Chrome release! The wait is over, everyone. :) [release notes]

Today, Zeldman issued an ultimatum that we've all been feeling recently:
Chrome needs to support @font-face immediately.

It's true, every major browser supports @font-face:

  • Internet Explorer: since IE5
  • Firefox: since FF3.5
  • Safari: since Safari 3.2
  • Opera: since Opera 10

But..
Google Chrome currently does not enable @font-face linking to ttf and otf.

It actually does support SVG fonts in a @font-face declaration. View this demo in Chrome or Chromium to see svg fonts in action. Divya has some great research around fonts and SVG if you're interested in more.

You can turn it on, at will

You can enable web fonts with an executable switch: −−enable-remote-fonts.

On Windows, you can tweak the shortcut path, like so.
With Chromium on OS X, you use Terminal to launch:

/Applications/Chromium.app/Contents/MacOS/Chromium --enable-remote-fonts

With proper Google Chrome on OS X, you need to escape the spaces:

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --enable-remote-fonts

With Chromium on Linux[1]:

chromium-browser --enable-plugins --enable-remote-fonts %U

Once you enable it, all @font-face stuff works just as you'd expect, including the bulletproof @font-face syntax [demo] and the Nice Web Type demos.

But we need web fonts working by default

Wait, so why is this wonderful feature disabled by default? Security review. Ian Fette, the program manager of Chrome, indicated that they need to explore how do webfonts in a "reasonably safe manner". So that's the holdup.
This ticket on the Chromium bug tracker tracks the feature being enabled by default.

Okay, so when do we get our toy? Soon, in fact!

Chrome is my default browser, so my patience on this issue ran dry recently. I emailed Takuya, an engineer at Google Japan, who is working on this and he said:

We are almost done. The code is under review internally within Google. I'm expecting to make it public no later than a week or so.

So I expect we'll be seeing @font-face support enabled by default in the Chrome dev builds soon. Based on their release schedule I think it'll be near the end of the year when we see it in Chrome stable. That's good news; let's hope we see it sooner.

2009.10.19 : The ticket tracking @font-face on by default gained the Milestone-4 label, indicating it will be included in Chrome 4 Stable.

2009.11.04: The Chromium team has released ots - an OpenType sanitizer library meant to clean any security concerns from a font file included via @font-face. They have also filed a bug upstream with WebKit to integrate this code at the Webkit level. Finally we see the fruit of their security review.

2009.11.18: Remote fonts are now enabled by default!!! This should only be in the dev builds for now. I'll update when it makes it to beta builds and eventually the stable. But right now it still looks like we'll see this in version 4 stable. (Nov 21: confirmed its in dev builds.. starting with version 4.0.249.4 [blog post], [rev 32300])

2009.12.09: @font-face support is now in the Chrome Beta of both Windows and Mac.

2010.01.25: @font-face support is now in the Windows Chrome Stable release! [release notes]

Paul Irish front-end development, typography

Avoiding the FOUC v3.0

September 23rd, 2009

FOUC is an unwelcome guest to your soirée of intertube funtimes. He comes in and distracts users eyes with things they shouldn't be seeing, and then departs ever so quickly. We don't like him.

So you've likely seen code like this:

<body>
  <script>document.body.className += 'js';</script>

No good. Scripts in the body block rendering so we can do better[1]:

<head>
  <script>document.documentElement.className += 'js';</script>

Here we'll be adding the class to the HTML element instead of the body, which we have access while we're in the HEAD. (Naturally CSS works just fine with a html.js selector, though this doesn't validate in HTML4)

But here's my big hang-up:
I prefer to write unique css for the no-javascript user. I don't want to be writing .js in front of every selector for my basic accordion/carousel/etc widgets. It's terribly tedious. I really just want a .no-js hook.

My solution:

<html class="no-js">
<head>
  <script>(function(H){H.className=H.className.replace(/\bno-js\b/,'js')})(document.documentElement)</script>

The markup has a no-js class on HTML by default but we'll very safely change that to 'js' inside the head. That compressed line of javascript is basically:

document.documentElement.className = document.documentElement.className.replace(/\bno-js\b/,'js');

But I make it small as it's one of the only scripts that should run in your head. Because everyone has their scripts near their </body> tag, right?

We use the same approach in Modernizr, because we want the classes to be all set on the HTML element right when the BODY content starts loading in. Fight the FOUC!

Paul Irish front-end development, javascript

Bulletproof @font-face syntax

September 4th, 2009

Let me introduce you to the best way to do your @font-face definitions:

@font-face {
  font-family: 'Graublau Web';
  src: url('GraublauWeb.eot');
  src: local('Graublau Web Regular'), local('Graublau Web'), 
         url('GraublauWeb.otf') format('opentype');
}

I'll circle back to why this is the best possible solution but let's first review the other techniques' weaknesses. Of course, the problem at the center of this is that IE needs an .eot font, and the other browsers must take a .ttf or .otf. Okay, let's see what we got here…

Conditional comments (via)

<style type="text/css" media="screen">
@font-face{
  font-family:'Graublau Web';
  src: url('GraublauWeb.otf') format('opentype');
}
</style>
<!--[if IE]>
<style type="text/css" media="screen">
@font-face{
  font-family:'Graublau Web';
  src: url('GraublauWeb.eot');
}
</style>
<![endif]-->

Ugh. Seriously? We'd have to drop that in every html file or have unique iefonts.css files. No fun. Also, ugly.

Double declarations (via)

@font-face{
  font-family:'Graublau Web';
  src: url('GraublauWeb.eot'); /* here you go, IE */
}
@font-face{
  font-family:'Graublau Web';
  src: url('GraublauWeb.otf'); /* everyone else take this */
}

The problem here is that, as Andrea points out, IE will actually download the .otf file. We can't have extra HTTP connections, so this is typically the solution:

@font-face { 
  font-family: 'Graublau Web';
  src url('GraublauWeb.otf') format('opentype'); /* IE no comprende format()! */
}

Because after all, IE doesn't understand the format hint, right? It's true. But what really happens is that IE does a request for this filename:
GraublauWeb.otf')%20format('opentype

Oops, looks like someone forgot a ? in their regular expression! But hey, a 404 is a lot better than grabbing a file that's 20-100k. Let's kill that 404:

Mo’ Bulletproofer (via)

@font-face{
  font-family:'Graublau Web';
  src: url('GraublauWeb.eot'); /* here you go, IE */
}
@font-face{
  font-family:'Graublau Web';
  src: url(//:) format ('no404'), url('GraublauWeb.otf') format('opentype'); /* tricky! */
}

Richard Fink proposed this alternate syntax actually as a response to this post, but I've included it back here. The trick is to use url(//:), to prevent IE from 404'ing on the ttf/otf file. In his article he lists a few reasons why he prefers the semantics of this alternative. I understand the argument, but I don't like repeating myself, so I'm gonna keep trucking:

The local reference

@font-face {
  font-family: 'Graublau Web';
  src: url(GraublauWeb.eot);
  src: local('Graublau Web Regular'), url(GraublauWeb.otf) format('opentype');
}

Much more concise and clean. Here, non-IE browsers skip any .eot file and move on. IE will try to parse the second src value, but it can't understand the local() location nor the multiple locations, so it resorts to the EOT instead. Worth noting that IE will always dive to the last src:url() value to start, so this won't work.

src: url(GraublauWeb.eot);  
src: url(GraublauWeb.otf); /* Yeah IE will only try this one. :( */

The other benefit.. if it just so happens that a user actually has your custom font installed, this'll save them the download. The one catch is that Safari on OS X will use only the Postscript name instead of the full font name; so when they differ, include both names:

Bulletproof @font-face

@font-face {
  font-family: 'Graublau Web';
  src: url('GraublauWeb.eot');
  src: local('Graublau Web Regular'), local('Graublau Web'), 
         url('GraublauWeb.otf') format('opentype');
}

Bulletproof @font-face: Smiley variation

@font-face {
  font-family: 'Graublau Web';
  src: url('GraublauWeb.eot');
  src: local('?')
         url('GraublauWeb.otf') format('opentype');
}

Added 2010.02.04: There has been concern over specifying local font names. The primary reason is that you cede control to the user's machine, potentially showing a locally installed font instead of the one you want to serve. While that will load faster, there's a very small chance the file could be wrong.

To account for this gotcha, I've specified a local font name of . Yes, it's a smiley face. The OpenType spec indicates any two-byte unicode characters won't work in a font name on Mac at all, so that lessens the likelihood that someone actually released a font with such a name. This technique is recommended if you think a locally installed version of this font is not in your best interest.

Demo

I've added a test page with a few syntax variants here for crossbrowser testing

Additional notes and gotchas:

  • Including a font-variant property inside the definition will cause it to not work in Safari (4.0.3 tested) as well as IE 6-8. (Thanks Sid)
  • Including a font-style property the definition is safe and the definition will still succeed with all browsers, however IE ignore what you define it as.But if you want a bold or italic style of a font to display, you'll need to make two definitions. Read the It Takes Two, Baby section on Nice Web Type's how to use css font face article
  • Opera will fail if you do not use quotes (single or double) in your local() font name. So: local('Use Quotes'). I've filed this bug with Opera as it's a spec violation. Thank you to Scott Kimler and Richard Fink for helping with the tireless research on Opera's quirks.
  • Safari permission error? Some people experience a dialog asking for permission to use a local font. This only happens in webkit. [screenshot]
    • Thibault Bardat-Bujoli indicated that this behavior is due to Linotype FontExplorer X. For any font added but not 'activated', it will intercept requests to use it. You can disable this behavior within the FontExplorer UI [jpg]. I have heard no reports of this behavior on machines lacking FontExplorer
  • Chrome? A few rumors are going around that a Chrome beta or dev build has @font-face support. There is no install of Chrome that has @font-face enabled by default [actually, it's in dev builds now!], however you can enable it in Chrome 3 with an executable switch. I'm keeping this page on @font-face and Google CHrome up to date with all the details.
  • You can feed FF, Opera and Safari a truetype but specify it as format('opentype') and it's just fine. So for all intents and purposes, if your font is opentype or truetype, the format hint is optional.
  • The font name that specified in your @font-face declaration cannot exceed 31 characters in length. IE will fail on anything larger.

SVG? WOFF?

Since Google Chrome won't have typical @font-face support until version 4, we can snag it early by serving it SVG fonts. WOFF is a new format that is officially supported in Firefox 3.6 Can we integrate those into this syntax? Definitely.

@font-face {
  font-family: 'Graublau Web';
  src: url('GraublauWeb.eot');
  src: local('Graublau Web Regular'), local('Graublau Web'),
    url("GraublauWeb.woff") format("woff"),
    url("GraublauWeb.otf") format("opentype"),
    url("GraublauWeb.svg#grablau") format("svg");
}

The order of those is deliberate and discussed in the comments here. Hat tip to Snook for being the first to drag SVG into the party. Font Squirrel and Nice Web Type have also been very thoughtful in their work.

I'm confused and lazy. Help?

Want to absorb the benefits of this article instantly? Use Font Squirrel's awesome @font-face generator. It does all of this for you, and more. If you're less lazy, read through Nice Web Type's How To for all the deets.

2009.09.10: Esta entrada del blog en español: Sintaxis de @font-face | CSSBlog ES

2009.09.11: Una buona panoramica e questa tecnica in italiano: font-face e Webfonts: come usarli

2009.09.16: I've updated the article with the Mo' Bulletproofer syntax as well as some more detailed gotcha's and notes.

2009.09.18: This blog article has been translated to Japanese

2009.09.22: Added details around the Safari permission error, which Thibault Bardat-Bujoli tracked down to the Linotype FontExplorer X app.

2009.11.08: New sections for SVG/WOFF and the Font Squirrel generator. Link to Nice Web Type's How To article for doing italic along with normal.

2009.11.17: Note on font name length from FontSquirrel.

2009.12.02: Update on Chrome support with link to Chrome and @font-face: it's here!

2010.02.04: Added the smiley variation.

Paul Irish front-end development, typography

@font-face feature detection

August 20th, 2009

As I'm piecing together a very comprehensive solution for using custom typefaces online, one of the crucial aspects is determining what browsers support @font-face.

My requirements for this detection were:

  • No browser userAgent sniffing
  • No extra HTTP request required
  • The test must be synchronous, no race conditions or HTTP requests
  • Must be performant with a small footprint, natch
  • Results should match the latest research on compatibility

I quickly tried:

!!window.CSSFontFaceRule

This test works great in FF2+, Safari and Opera. But it fails in IE (bug surprise) and Chrome gives a false positive.

The code

What follows is the best test for @font-face support I have found:

 
/*!
 * isFontFaceSupported - v0.9 - 12/19/2009
 * http://paulirish.com/2009/font-face-feature-detection/
 * 
 * Copyright (c) 2009 Paul Irish
 * MIT license
 */
 
var isFontFaceSupported = (function(){
 
 
    var fontret,
        fontfaceCheckDelay = 100;
 
		// IE supports EOT and has had EOT support since IE 5.
		// This is a proprietary standard (ATOW) and thus this off-spec,
		// proprietary test for it is acceptable. 
    if (!(!/*@cc_on@if(@_jscript_version>=5)!@end@*/0)) fontret = true;
 
    else {
 
    // Create variables for dedicated @font-face test
      var doc = document, docElement = doc.documentElement, 
          st  = doc.createElement('style'),
          spn = doc.createElement('span'),
          wid, nwid, body = doc.body,
          callback, isCallbackCalled;
 
      // The following is a font, only containing the - character. Thanks Ethan Dunham.
      st.textContent = "@font-face{font-family:testfont;src:url(data:font/opentype;base64,T1RUTwALAIAAAwAwQ0ZGIMA92IQAAAVAAAAAyUZGVE1VeVesAAAGLAAAABxHREVGADAABAAABgwAAAAgT1MvMlBHT5sAAAEgAAAAYGNtYXAATQPNAAAD1AAAAUpoZWFk8QMKmwAAALwAAAA2aGhlYQS/BDgAAAD0AAAAJGhtdHgHKQAAAAAGSAAAAAxtYXhwAANQAAAAARgAAAAGbmFtZR8kCUMAAAGAAAACUnBvc3T/uAAyAAAFIAAAACAAAQAAAAEAQVTDUm9fDzz1AAsD6AAAAADHUuOGAAAAAMdS44YAAADzAz8BdgAAAAgAAgAAAAAAAAABAAABdgDzAAkDQQAAAAADPwABAAAAAAAAAAAAAAAAAAAAAwAAUAAAAwAAAAICmgGQAAUAAAK8AooAAACMArwCigAAAd0AMgD6AAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAEZIRAAAQAAgAC0C7v8GAAABdv8NAAAAAQAAAAAAAAAAACAAIAABAAAAFAD2AAEAAAAAAAAAPAB6AAEAAAAAAAEAAgC9AAEAAAAAAAIABwDQAAEAAAAAAAMAEQD8AAEAAAAAAAQAAwEWAAEAAAAAAAUABQEmAAEAAAAAAAYAAgEyAAEAAAAAAA0AAQE5AAEAAAAAABAAAgFBAAEAAAAAABEABwFUAAMAAQQJAAAAeAAAAAMAAQQJAAEABAC3AAMAAQQJAAIADgDAAAMAAQQJAAMAIgDYAAMAAQQJAAQABgEOAAMAAQQJAAUACgEaAAMAAQQJAAYABAEsAAMAAQQJAA0AAgE1AAMAAQQJABAABAE7AAMAAQQJABEADgFEAEcAZQBuAGUAcgBhAHQAZQBkACAAaQBuACAAMgAwADAAOQAgAGIAeQAgAEYAbwBuAHQATABhAGIAIABTAHQAdQBkAGkAbwAuACAAQwBvAHAAeQByAGkAZwBoAHQAIABpAG4AZgBvACAAcABlAG4AZABpAG4AZwAuAABHZW5lcmF0ZWQgaW4gMjAwOSBieSBGb250TGFiIFN0dWRpby4gQ29weXJpZ2h0IGluZm8gcGVuZGluZy4AAFAASQAAUEkAAFIAZQBnAHUAbABhAHIAAFJlZ3VsYXIAAEYATwBOAFQATABBAEIAOgBPAFQARgBFAFgAUABPAFIAVAAARk9OVExBQjpPVEZFWFBPUlQAAFAASQAgAABQSSAAADEALgAwADAAMAAAMS4wMDAAAFAASQAAUEkAACAAACAAAFAASQAAUEkAAFIAZQBnAHUAbABhAHIAAFJlZ3VsYXIAAAAAAAADAAAAAwAAABwAAQAAAAAARAADAAEAAAAcAAQAKAAAAAYABAABAAIAIAAt//8AAAAgAC3////h/9UAAQAAAAAAAAAAAQYAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAA/7UAMgAAAAAAAAAAAAAAAAAAAAAAAAAAAQAEBAABAQEDUEkAAQIAAQAu+BAA+BsB+BwC+B0D+BgEWQwDi/eH+dP4CgUcAIwPHAAAEBwAkREcAB4cAKsSAAMCAAEAPQA/AEFHZW5lcmF0ZWQgaW4gMjAwOSBieSBGb250TGFiIFN0dWRpby4gQ29weXJpZ2h0IGluZm8gcGVuZGluZy5QSVBJAAAAAAEADgADAQECAxQODvb3h/cXAfeHBPnT9xf90wYO+IgU+WoVHgoDliX/DAmLDAr3Fwr3FwwMHgoG/wwSAAAAAAEAAAAOAAAAGAAAAAAAAgABAAEAAgABAAQAAAACAAAAAAABAAAAAMbULpkAAAAAx1KUiQAAAADHUpSJAfQAAAH0AAADQQAA)}";
      doc.getElementsByTagName('head')[0].appendChild(st);
 
 
      spn.setAttribute('style','font:99px _,serif;position:absolute;visibility:hidden'); 
 
      if  (!body){
        body = docElement.appendChild(doc.createElement('fontface'));
      } 
 
      // the data-uri'd font only has the - character
      spn.innerHTML = '-------';
      spn.id        = 'fonttest';
 
      body.appendChild(spn);
      wid = spn.offsetWidth;
 
      spn.style.font = '99px testfont,_,serif';
 
      // needed for the CSSFontFaceRule false positives (ff3, chrome, op9)
      fontret = wid !== spn.offsetWidth;
 
      var delayedCheck = function(){
        if (isCallbackCalled) return;
        fontret = wid !== spn.offsetWidth;
        callback && (isCallbackCalled = true) && callback(fontret);
      }
 
      addEventListener('load',delayedCheck,false);
      setTimeout(delayedCheck,fontfaceCheckDelay);
    }
 
    function ret(){  return fontret || wid !== spn.offsetWidth; };
 
    // allow for a callback
    ret.ready = function(fn){
      (isCallbackCalled || fontret) ? fn(fontret) : (callback = fn);
    }  
 
    return ret;
})();

Download from github

The latest is always at: http://github.com/paulirish/font-face-detect
isFontFaceSupported.js Uncompressed - 4.3k
isFontFaceSupported.min.js Compressed - 3.1k

Usage

isFontFaceSupported() // will return a boolean indicating support
 
// you can also use with a callback,
//  it will be called 100ms later which is adaquate for Gecko and Webkit to properly use the data-uri'd font.
isFontFaceSupprted.ready(function(bool){
  // bool is a boolean that indicates support
});

Sorry. :(

You'll spot the IE conditional compilation in there. I don't like it either, but I'm unaware of any other workable approach (that doesn't pull in an .eot) to test for @font-face support. If you have an idea, please share it!

On the approach

I first use the Web Font Optimizer to subset a truetype font to only contain the period (.) character (2.2k file!), then send it through a data URI converter, then chuck it into a style tag. I test the width of a span of text without the custom font, and then again with the custom font. If the values are different, we can assume @font-face is supported and works.

With a trip through the YUI Compressor, the script is 3.5k3.1k. If you have any ideas on bringing that figure down, I'd love to hear 'em.

Great! Any disadvantages?

Yeah there's one big one. Both Gecko and Webkit load in a data-uri font asynchronously, so the test may give a false negative if you call isFontFaceSupported() immediately afterwards:

<script src="isFontFaceSupported.min.js"></script>
<script>
  if (isFontFaceSupported()) ... // this may report a false negative.
 // that's why we have the isFontFaceSupported.ready() callback mechanism

I'm not terribly happy with this asynchronous delay, so I've written an alternative that uses browser userAgent sniffing. This practice is not recommended and is not terribly future-proof, but it's the only synchronous solution available.

isFontFaceSupported() - sniffing variant
/*!
 * isFontFaceSupported - Sniff variant - v0.9 - 12/19/2009
 * http://paulirish.com/2009/font-face-feature-detection/
 * 
 * Copyright (c) 2009 Paul Irish
 * MIT license
 */
 
/* Browser sniffing is bad. You should use feature detection.
   Sadly the only feature detect for @font-face is 
   asynchronous. So for those that *need* a synchronous solution,
   here is a sniff-based result:
*/
 
var isFontFaceSupported = function(){
 
  var ua = navigator.userAgent, parsed;
 
  if (/*@cc_on@if(@_jscript_version>=5)!@end@*/0) 
      return true;
  if (parsed = ua.match(/Chrome\/(\d+\.\d+\.\d+\.\d+)/))
      return parsed[1] >= '4.0.249.4';
  if ((parsed = ua.match(/Safari\/(\d+\.\d+)/)) && !/iPhone/.test(ua))
      return parsed[1] >= '525.13';
  if (/Opera/.test({}.toString.call(window.opera)))
      return opera.version() >= '10.00';
  if (parsed = ua.match(/rv:(\d+\.\d+\.\d+)[^b].*Gecko\//))
      return parsed[1] >= '1.9.1';    
 
  return false;
 
}

This guy is also on github

2009.09.24: updated the code, and threw it all on github. callback style makes its debut here. This code matches the exact same implementation that's in Modernizr 1.0

2009.12.18: Added a useragent sniffing alternative for those who want reliable synchronous detection.

2009.12.19: New, smaller font file (Thanks Ethan Dunham). The file is now 15% smaller. Script does not remove the extra element it adds to the DOM now, as to assure more accurate results.

Paul Irish front-end development, javascript, typography

Caching and Google's Ajax Libraries API — Cache your jQuery

August 14th, 2009

Leveraging Google's free hosting of common javascript libraries seems to be getting more popular. While you should be serving all javascript concatenated and minified together, the free hosting is nice for quick jobs or more minimal projects.

The versioning system they devised is a very clever way to always serve you the most up-to-date script. For example, you request version 2 of SWFObject and it'll currently deliver 2.2, but in the future you'll always get the most recent 2.x release.

I did a bit of research on how they handle these cases, and since these facts aren't elsewhere, they needed a home. :)

The current caching rules are as follows:

Request Response cached for
/1.3.2/jquery.min.js one year
/1.3/jquery.min.js one hour
/1/jquery.min.js one hour

* jQuery URLs used only for illustration purposes. It's the same case with all scripts' minor/major versions
* Minified and unminified files are treated the same

Previous to now, using the google.load('jquery','1.2.6') technique was the only way to ensure the script stayed considerably cached. Direct path-based access scripts were only cached for one day. But no worries, because all is better now.

Paul Irish front-end development

The direction forward with web fonts

August 11th, 2009
Comments Off

In the current discussions around fonts on the web, there is much confusion between the techniques. Most seem to think that TypeKit and .webfont are our only options. They are not, but the rest of the landscape is quite busy.

Things have been moving very quickly in the last three weeks, so let me break it down like this:

  • Webfont services: TypeKit, fontdeck, Typotheque
  • Proposals: EOT-Lite, .webfont, ZOT, webOTF
  • Implemented standards: @font-face using EOT and TTF
  • JavaScript-based font solutions: sIFR, Facelift, Cufón

The commercial webfont services players

While many have considered TypeKit as an alternative to .webfont, it's just a smart implementation of CSS and JavaScript along with a shop and licensing model. I agree with Pablo Impallari who commented:

You don’t need typekit, .webfont or any other solution. You can start using real fonts on the web right now.

Typekit makes a somewhat complicated implementation drop-dead easy, but if you've used sIFR before, than I'm confident you can handle this on your own.

The licensing legwork that TypeKit is doing is a significant value-add and may be worth it for people who don't want to deal directly with font resellers. I'm quite interested in how the smart folks at Clearleft expect to differentiate their competing service, fontdeck.

Typotheque and Kernest are also new entrants to watch, both created by font shops. Both seem to only license their own foundries' typefaces, so their library size may end up being quite small, but I can say right now Typotheque's offering looks strong.

At the same time, we've had web font services already: Fontburner and Flir Premium, but they never really gained popularity, so I'm surprised people expect such a different outcome from these new players.

The EOT-Lite and .webfont proposals

The general complaint from the type community around non-EOT @font-face is that the naked font is so accessible, anyone could trivially take it off a webserver and install it on their machine. These two proposals offer a “garden fence” approach to protection; it's still quite easy to get inside and snag the font, but it's harder than if there were no protection at all.

.webfont, the format proposed by Tal Leming and Erik van Blokland is a great compromise solution: basically a zip file containing both an xml file of metadata and the font. While it uses the same css @font-face syntax, and everyone seems to love it, having it work in all browsers is at least three years off.

EOT-Lite, on the other hand, seems to be covered much less in roundups to date. The basic idea is that it's the same as EOT but without the two major complaints of the format: domain binding and MTX compression. (Interesting as, the compression's patent owner is offering to free it up.)

The huge plus of EOT-Lite is that the format works, right now, in IE4-IE8. Adobe, Monotype, Microsoft and a cadre of type shops support it. Perhaps surprising for some, Mozilla is also quite involved in the EOT-Lite discussion, not only helping to define the spec, but also making a test build of Firefox that handles the new format.

ZOT is a new format proposed by Mozilla; essentially TTF with compression. It's well considered, but as .webfont comes with the same advantages and already has a wave of support, I think ZOT is best left as an academic discussion. Oh, and Berlow's OpenType permissions table – which would have been a great idea to have in 2000, but not now.

Update 2009.08.10: .webfont and ZOT merged their proposals. It's now called WebOTF.

The @font-face standard

By my calculations, the current implementation (using EOT or TTF/OTF) covers ~70% of users. When Firefox 3.0 users upgrade to 3.5 that figure will increase to ~90% of users (I bet we'll see that within six months). Things still do visually look a little different across browser implementations, but they currently work cross-browser and with fixes like forcing Cleartype on for web fonts in Firefox, render quality is improving steadily.

/* it's this easy: */
@font-face {
  font-family: 'Gentium';
  src: url(Gentium.eot); /* EOT for IE */
}
@font-face {
  font-family: 'Gentium';
  /* IE ignores this one because of the format value */
  src: url(Gentium.ttf) format("opentype");
}
h1,h2,h3 { font-family: 'Gentium', Tahoma, sans-serif;

I generally side with the concerns of type foundries here, rather than the Fuck The Foundries crowd. I want myself and other designers to have access to the best of typography, but understand the fonts used for Firefox/Webkit are a little too naked at this point. While we're waiting for the rest of this to pan out we may see a new market of type designers that are comfortable with naked fonts (like David B?ezina), but I'm skeptical about the efficacy of that.

JavaScript-based custom font solutions

We've had sIFR for nearly 5 years and I'm glad we have, but we now have better options. After significant research I think Cufón is the best library in this space; it's small, clever, and very performant. However, many foundries aren't ready to license their typefaces for use with Cufon. Facelift is a great alternative here, as it doesn't expose the font data to the browser (instead generating PNGs via PHP), thus very licensing-friendly.


These libraries will be useful in bringing custom fonts to older browsers (currently: Firefox 3.0, Chrome, and Opera 9), but still lack flexibility when it comes to rtl languages.

It's also possible that they won't be treated only as a fallback solution. If foundries remain unwilling to license for the naked @font-face implementation in Firefox and Webkit, we may have no choice but to use Cufón while we're waiting for these browsers to adopt EOT-Lite or .webfont. In fact, Monotype's web embedding EULA currently allows use with siFR and Cufón, as long as there is domain-binding.

Conclusions

I don't think webfont services are the future, but I do think the landscape is hairy enough now to convince web developers to take the easy route by relying on a TypeKit or Fontdeck for their custom type. Taking advantage of the best techniques available isn't insurmountable without a hosted webfont service, and I think we'll see developers going it alone with their own implementations and licensing directly with the font resellers.

I believe EOT-Lite is the right direction for webfonts right now. It already works in the most stubborn browser, and since Firefox just released a test build with support for EOT-Lite, it's looking more reasonable than ever. It's also quite interesting that after the months of debate at the W3C surrounding Microsoft's proposal of making EOT the standard, it took quite some time for the sensible proposal of EOT-Lite to emerge. I guess both sides had to soften a little. :)

This is a cross-post, originally appearing on Molecular Voices. If you have any comments or questions, please leave a comment there.

Paul Irish front-end development, typography