This is an archive site. For the recent posts, visit

Ordered List


Sep 2 2008

FancyZoom Meet Prototype

I hate lightboxes. Everyone who knows me, knows this. When I saw Cabel Sasser’s FancyZoom, a similar interaction, I liked the idea but not the exact implementation, so I rewrote it.

So what didn’t I like about Cabel’s? Nothing big and nothing deal breaking, just more a matter of preference. First, I didn’t like that it used AJAX. I tend to lean towards the side of rendering everything and then showing and hiding, rather than loading stuff with AJAX. I’m not a fan of waiting once a page is loaded, so my version works with any HTML already included on the page.

Second, Cabel, being the rebel that he is, built his from scratch with no use of any JavaScript libraries. That is cool and all, but I almost always have Prototype and Scriptaculous included. Cabel’s version without Prototype is two scripts that weigh in at 36k. My version with prototype is only 12k. Granted, we are doing things a bit differently, and mine has the overhead of Prototype and Scriptaculous, but like I said, I’d have that overhead with or without the fancy zoom.

Third, Cabel’s implementation only works for images and it loads them via AJAX (to save initial page weight). I think that the zoom interaction is pretty interesting so I didn’t want a version limited to just images. Mine supports pretty much any html you can throw in a div (images, text, flash, etc.). The only caveat is the html must be on the page somewhere, at this point.

Fourth, and final, is that I liked Apple’s rounded corners, as opposed to the original fancy zoom’s square edges. Sexy. You can see it on Apple’s site (click on the watch video button) or just take a gander at the screenshot below.

iPhoto Zoom


As always, I’ve whipped together a little demo site for you.

Fancy Zoom

A Few Snippets

I won’t go into all the code, as it would take forever, but I’ll mention a couple of snippets from fancy zoom.

Object.extend(String.prototype, {
  // if a string doesn't end with str it appends it
  ensureEndsWith: function(str) {
    return this.endsWith(str) ? this : this + str;
  // makes sure that string ends with px (for setting widths and heights)
  px: function() {
    return this.ensureEndsWith('px');

Object.extend(Number.prototype, {
  // makes sure that number ends with px (for setting widths and heights)
  px: function() {
    return this.toString().px();

When you are setting widths and height in prototype you always have to have ‘px’ on the end. I got tired of adding it, so using the snippets above I can do things like the code below, and I’m guaranteed to always end up with the correct unit.

180.px(); // => '180px'
'180'.px(); // => '180px'
'180px'.px(); // => '180px'

Also, for the first time I used Effect.Parallel, which allows you to run multiple effects at once really easily. In this case, I’m running Effect.Appear, Effect.Move and Effect.Morph in sync to make the transition feel like it is jumping off the page.

At any rate, this was an interesting project and I’m sure I’ll be updating it with more goodies as I use it. The code and examples are up on Github so feel free to fork and give back. Hope it comes in handy for you.