Attention:I pre-apologize for any strange typos, language/grammar, or otherwise confusingness of this article. I PROMISE, that with the full release of my solution will be coherant documentation of how to impliment.
So the project I’m working on at my full time gig is really cool in a number of respects, but from where I’m involved with the project I get to play around in some of the most visually intense, technically challenging layouts of my career so far. Lots of theme-based layouts that rely heavily on textures, which makes a bulletproof layout difficult enough, and practically IMPOSSIBLE to achieve without the use of png alpha transparency.
Enter the bain of my existance.
Internet Explorer, along with it’s wonderful support of web standards, does a real number on png’s with alpha transparency. An example of how it botches, the left one is how the png is supposed to appear, the right one is IE’s version of the EXACT SAME FILE.
yeah, not pretty.
so what’s a developer to do?
well, there’s a number of javascript based png fixes out there, and the one we had originally chosen worked nicely, so long as it was only for a couple of pngs at a time.
Without getting too involved with how it worked, it essentially walked the DOM to find every image, determined which ones had a png extention, and then replaced the image with a “span” tag that had the same properties (dimensions, classes, id, etc) and applied the activex alpha transparency filter to the background of that object.
Hackey, relied on activex, and the bigger problem was that it got slow with more and more pngs to process. The png’s would appear like the one above (all grey’d out over the transparent regions) for a split second before being corrected. On a mainstream website, this was TOTALLY unacceptable.
So i got to thinking…why not use Flash’s native transparency support to my advantage? I went over and talked to one of my partners in crime, Arthur Dickerson, flash genious and all around awesome designer. I had Arthur whip up a swf that would take a few parameters:
- url to an image file
- the image dimensions
Effectively, I should be able to embed a flash object on the page that calls in the image, scale the flash around the image, and flash will handle the transparency nice and pretty.
The resulting swf is 400 bytes. That’s right, less than half a kb. So I hooked up the the embed using SwfObject from deconcept, and sure enough it worked beautifully. Next step: make images that are buttons, clickable.
Ok Arthur, make it so that I can pass in a URL, and if it exists as a parameter, the image will automatically become clickable.
Done.
So now we’ve got the flash handling all of the leg work…but the embed tag is kinda messy. It’d be way nicer if I could place the images on the page just like I normally do, and have the embed tags replace them, ahem, transparently.
Javascript to the rescue, and time to employ some clever little tricks to get the images out and the swf embeds, in their place.
First trick is to cut down on the time necessary to loop through EVERY image on the page. Simply, I gave any img tag that housed a png formatted image a class=â€png†attribute. Done.
Now by using the document.getElementsByClassName, I can dig up every png on the page snappy as ever. Looping through and grabbing all of the attributes, and then passing them around to get the DOM prepped to write out the embed tag using the handy dandy swfObject utility. One of the first “quirks†about this version is the fact that any img tag that is going to have this treatment MUST have some sort of element wrapper: a <p>, <span>, <div>, <h1>, something of the sort. This is so that the swfObject code has something to inject the flash embed object code into. Again, the handling of all of this is transparent to the XHTML page.
But now I’m back where I started…the pngs are being swapped out for something that’s not a png. If theres a lot of png’s on the page, then it starts to show lag.
So I bounced the whole idea past another cohort of mine, Ryan over at Concept64. He suggested this fix up in the head of the document, before calling my png->swf function:
document.write("<style>img.png {visibility:hidden;}</style>");
since this is being done via javascript, non javascript folks still get the images (though they will look crappy in IE). Folks with IE and javascript will use CSS to hide the png images using the same class I used in my looping utility, but not lose their place in the dom, or their dimensions.
So before the dom even gets a chance to display the crappy looking pngs instead of the pretty swf replacements…css turns them off.
Brilliant. Currently I plan to only employ the technique on browsers where it’s necessary…and by browsers, i mean browser, being IE. Though I have tested it on multiple browsers on various platforms, including a 500mHz g4 powerbook in safari, and in IE on a bottom of the line e-machine. works flawlessly every time. sweet.
Next steps are:
- refactor/clean up javascript.
- clean up link handling
- include javascript function calls for onmouseover, onmouseout, and onclick events
- work on some extra levels of degradation…for noflash and nojavascript
Anything else you think you might like to see?
as soon as everything is cleaned up, I’ll be posting all of the source here under CC license. More importantly, clean and thorough documentation (unlike this rambling mess) will be included.
Keep your eyes peeled. More goodness to come.
p.s. im thinking about giving it a stupid web2.0 name, like pingr. actually, i was thinking of calling it pongr, since it takes the p(i)ng and returns something a bit more useful….a pong, if you will…
but i’m open to suggestions.