Archive

Author Archive

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

How to fulfill your own feature request -or- Duck Punching with jQuery!

February 23rd, 2010

Wait, what? Well first, duck punching is another name for monkey patching. Monkey Patching is a technique to "extend or modify the runtime code of dynamic languages without altering the original source code." But then some Ruby hackers decided that since we rely on duck typing so often, a more proper name was in order:

… if it walks like a duck and talks like a duck, it’s a duck, right? So if this duck is not giving you the noise that you want, you’ve got to just punch that duck until it returns what you expect.[1]


In jQuery we can use this to great effect. We'll employ an AOP-like approach (aspect-oriented programming), maintaining the original function but wrapping it with our enhancement.

Example 1: Adding color support

(This is a silly example, but hopefully it explains the idea. )
You're fully aware that you can use certain color names in HTML. But sadly, everyone's favorite Crayola™ color, Burnt Sienna, can't play along. Well, not until now…

(function($){
 
    var _oldcss = $.fn.css;
 
    $.fn.css = function(prop,value){
 
        if (/^background-?color$/i.test(prop) && value.toLowerCase() === 'burnt sienna') {
           return _oldcss.call(this,prop,'#EA7E5D');
        } else {
           return _oldcss.apply(this,arguments);
        }
    };
})(jQuery);
 
// and using it...
jQuery(document.body).css('backgroundColor','burnt sienna')

Let's walk through that a little bit slower, shall we?

First we start off with a self-executing anonymous function that makes a happy closure while remapping jQuery to $:

(function($){
    // ...
})(jQuery);

Now we save a reference to the old css method as a local variable, and set up our new definition for that method:

    var _oldcss = $.fn.css;
 
    $.fn.css = function(prop,value){
        // ....
    };

Inside our function definition we have an if statement that breaks up two code paths, the new enhanced route, and the old default:

        // if the user passed in backgroundColor and 'burnt sienna'
        if (/^background-?color$/i.test(prop) && value.toLowerCase() === 'burnt sienna') {
 
            // call the old css() method with this hardcoded color value
            return _oldcss.call(this,prop,'#EA7E5D');
        } else {
            // otherwise call the old guy normally, taking his return value and passing it on.
            return _oldcss.apply(this,arguments);
        }

Scroll back up to see the whole thing together. Can you dig it?

Example 2: $.unique() enhancement

$.unique only winnows an array of DOM elements to contain no duplicates, but what if you want all non-duplicates of any type? Here's an upgrade:

(function($){
 
    var _old = $.unique;
 
    $.unique = function(arr){
 
        // do the default behavior only if we got an array of elements
        if (!!arr[0].nodeType){
            return _old.apply(this,arguments);
        } else {
            // reduce the array to contain no dupes via grep/inArray
            return $.grep(arr,function(v,k){
                return $.inArray(v,arr) === k;
            });
        }
    };
})(jQuery);
 
// in use..
var arr = ['first',7,true,2,7,true,'last','last'];
$.unique(arr); // ["first", 7, true, 2, "last"]
 
var arr = [1,2,3,4,5,4,3,2,1];
$.unique(arr); // [1, 2, 3, 4, 5]

A Duck Punching Pattern

Here's the bare pattern. Feel free to use this as the basis of your own:

(function($){
 
    // store original reference to the method
    var _old = $.fn.method;
 
    $.fn.method = function(arg1,arg2){
 
        if ( ... condition ... ) {
           return  .... 
        } else {           // do the default
           return _old.apply(this,arguments);
        }
    };
})(jQuery);

What else could I use this for?

Some other uses I've had or seen for this sort of thing:

So while you're free to file a feature request of jQuery, most of the time you can actually enhance jQuery's methods yourself! Enjoy.

Paul Irish jquery

On jQuery's live()

January 22nd, 2010

Since the release of 1.4, there's been a lot of discussion about live(). Now that it's almost as fully featured as bind(), it's getting quite a workout.

One of the larger calls to action is to introduce $.live(selector,eventType,handler). There are two primary reasons I've seen behind this proposal:

  1. There is a performance hit for the initial selection in $('a.whatever').live(.. that isn't neccessary
  2. live() cannot work on any arbitrary collection of DOM elements in jQuery object, as a side effect of a very different internal operation, thus providing an inconsistent developer experience than all other $.fn.foo methods.

$.live for performance

Sizzle is used to find any matching elements before the live method discards them an only uses the jQobj.selector property and context. It's a waste, I agree. But you can avoid it. Zachleat posted this technique first. Then I stole a code snippet from @janl to show off in my jQuery Performance talk for jQCon. This inspired furf's jQuery.live() patch. And now jmar777 has resurrected that discussion.

I do not think the performance gain in $.live is worth adding it to jQuery core, by any means. Let's take an example.

Let's say we're dealing with $(selector).live('click',fn)

On every click on the page, the event is caught at the context.. the document. But evt.target points to the top-most element that was clicked on.
jQuery then traverses from evt.target through each ancestor of that node all the way up to document checking if (jQuery(elem).is(selector)).[source]

I think a reasonable estimated depth of evt.targets is like 8 (From the document to HTML element to BODY and so on.. a depth of 20 is not uncommon by any means). And lets say we have an average 5 clicks on a page.
That's 40 total checks against the selector (plus the original one done at bind time).
So in my opinion a 1/41 speed gain isn't worth changing the API.

Scoping the delegation a context, however has a much larger impact on performance: $(selector,elem).live('click',fn) Here, only clicks within the context are caught, so not only is the parent traversal depth much more shallow, but that entire sequence is avoided for all events occurring outside that area.

The current API to take advantage of this optimization requires code like $('a.awesome', $('#box')[0]).live(… Yuck! So I wrote a patch to deliver this same optimization to any ID-rooted selectors. (The perk being that everyone who learns #id-rooted selectors are fast for selecting get a related perf boost here). But as Justin Meyer pointed out in the comments, it's not as flexible as live() currently is.

$.fn.live cannot operate on any jQuery-wrapped collection of elements

$('a.foo').filter('.bar').live(... // fails
$('a.link').parent().nextAll().live(... // fails
$(this).live(... // fails

Quite simply, $.fn.live needs to be at the top of a chain to guarantee the .selector and .context properties of the jQuery object represent that set. Unlike other $.fn methods, live utilizes those properties and not the actual collection of elements that result from selection, traversing, and filtering.

$.live() and let $.die()

What are the possible solutions?

  1. Turn on a dirty flag in traversal methods, so if you try and live() that collection, it will throw an error.
  2. Deprecate $.fn.live and use $.live(selector[,context],type,handler)
  3. Use $.live to create a "live jQuery object" that defaults to live-bindings: $.live(selector,context).click(fn).mouseenter(fn).unbind("click") [source]
  4. Change $.fn.live to operate from a context: $(context).live('selector', event, fn) This bakes the performance benefit from above right in.

Any others? What do you guys think? Is there a solution that preserves backwards-compatibility while solving the issue?

btw- thx to jmar777, yehuda katz, ben alman, ajpiano, brandon aaron and julian aubourg for their great thoughts on the issue.

The people in this discussion got together and hashed out what would make sense. John Resig then landed a new delegate/undelegate API. It's good. :)

Paul Irish jquery

Updates from all around - Dec 2009

December 19th, 2009

A lot of the work I'm doing doesn't turn into new posts so here's a summary of what's been going on:

yayQuery

Since it was announced here, we've come a long way. We just put out our 7th episode (now in HD!). The show format has tightened up and we're putting a lot of time into making it even better. Follow us on twitter or subscribe to catch all the goodness. We also put out an entire episode devoted to what's coming in jQuery 1.4 (aka 1.MOAR), so peep it if you're curious.

jQuery Singalong plugin

I was a finalist at Boston's Music Hack Day with the jQuery Singalong plugin. It essentially allows you to add timed annotations to the HTML5 audio and video elements. (Also it was the first time I legitimately used javascript's Infinity :) In addition, I put out the (very!) alpha jQuery Bouncing Ball plugin. Check out the demos to get a taste

Modernizr updates

Faruk and I pushed out Modernizr 1.1, which can now detect what audio/video formats your browser supports, all sorts of HTML5 forms goodness, and some other ones like localStorage and applicationCache. We're delighted to be part of Mark Pilgrim's Dive into HTML5 book and pumped to help push the edge of progressive enhancement.

@font-face and webfonts

It's a rapidly changing landscape, so I've been keeping all my font-y posts up to date:

@font-face feature detection

I've updated the existing feature detection script to use a smaller file. (Thanks to the Font Squirrel for the help). You would use this script to detect if support is present or not; perhaps implement a Cufon fallback. These new improvements will make their way into Modernizr 1.2.

I've also added on a isFontFaceSupported browser sniffing alternative. The main benefit here is that you're guaranteed accurate results synchronously. (The true feature detection can't do that, though the new small size is much faster in Firefox.)

Other bits and bobs

The nice guys at that other jQuery Podcast had me on the show in November. I talked about, well.. basically all of the stuff above. :) It's a good show.

I tweeted about a new quick approach to a for loop:

for (var i = -1, len = arr.length; ++i < len; ) // the cool guy loop

The fun part is that the counting expression (the third part) is empty. It's faster than your standard loops, but reverse while() is still quicker. @jdalton beat me to this one, for the record.

Lastly, along with my writers, I've been keeping my mp3 blog Aurgasm fresh with new music you'll love. I've got a lot more things in the pipeline, so right after my Christmas and New Years jaunt around Germany, Denmark, and Scotland, you'll see them soon. Happy December ya'll.

Paul Irish javascript, jquery, typography

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

Announcing the Type Rendering project

November 30th, 2009

A short while ago, I pulled together some bright minds in the emerging web fonts scene: Tim Brown of Nice Web Type, Zoltan Hawryluk, and Ethan Dunham of Font Squirrel. I thought it would be wise to share notes and begin talking about cross-platform/browser type rendering (that lasagna of complexity), in order to clarify the entire process for ourselves and others and find ways to make web type look better.

Basically, I want @font-face text to look damn good.

Now we've set some goals and would like to open up the dialogue. We'll need your participation, and lots of expert advice, to fulfill these intentions. Follow Type Rendering on Twitter.

Check out How to Detect Font-Smoothing Using JavaScript to learn about an algorithm Zoltan has developed for determining whether a visitor's web browser uses font smoothing technology when rendering type.

If you want to see rich typography succeed, tell folks you care about how type looks on the web.

We'll be exploring all the layers involved in making sure web fonts are implemented in the best possible way. We'll need your help, too.

Paul Irish Uncategorized

Infinite Scroll 1.4 is out. Twitter-style now supported!

November 30th, 2009

I just released version 1.4 of the jQuery Infinite Scroll plugin. Along with that comes a new release of the wordpres plugin. A few small bugs were fixed in the wordpress code, improving compatibility with other plugins and themes.

I've also added the ability to manually trigger loading in new content. This allows you to do a twitter or facebook style of interaction where the user must click an element for the new data to come in.

A demo showing that functionality. The documentation of how to use this style is on the documentation page.

Paul Irish jquery

Introducing yayQuery - A jQuery podcast

November 6th, 2009

A few friends of mine got together to put together a new podcast we're calling…

yayQuery!

2009.11.13. Now visit the podcast at:
http://yayquery.com

In our inaugural episode I'm joined by Rebecca Murphey, Alex Sexton (of goto.js fame), and Adam Sontag (ajpiano). We talk about…

  • Underscore.js - a great utility belt (very handy for Ruby/Python folks), comes with John Resig's microtemplating script and lots more
  • Thickbox - Rest in peace. Also alternatives: Colorbox, jQuery UI Dialog
  • jQuery on mobile. Phonegap, XUI, jQTouch, going it alone
  • Anti-Pattern of the week: css(key,val)
  • $var and Hungarian notation
  • … and dancing

Moar?

We hope to do this again (and again) and make things better. We're also working on proper podcast feeds and a site.

But really this is an experiment, for now. We'd love any and all feedback.

… and follow us on twitter to get your fix!! @yayquery

Paul Irish jquery

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