(Yet Another) PNG Alpha Transparency Fix for MSIE6

Introduction

Among the (many) shortcomings of Internet Explorer 6 is its inability to handle PNG images with alpha transparency. Unfortunately, years after the release of Firefox and Internet Explorer 7, IE 6 still has a significant presence: in the first week of April 2009, it was the third most frequently-used browser to visit this site, after Firefox and IE 7. Alas, I do have a non-trivial amount of IE 6 traffic that I must contend with.

I was vaguely aware that there is a workaround for the IE 6 PNG problem, but it was something that I had never bothered to look into until very recently, when I took some screenshots, with alpha transparency, of HashCheck running on Windows 7. A little bit of Googling revealed a very wide array of methods for implementing Microsoft's AlphaImageLoader workaround. Yikes!

My Requirements

To sort through and evaluate all of the different options, I made a short mental list of what I thought were a simple set of requirements:

  1. Must be a client-sided solution: Using server-side scripting (with its associated overhead costs) to deal with a simple IE flaw is inappropriate and silly. Furthermore, I did not want to rely on user agent strings; IE's conditional comments—a client-side solution—are much more suitable.
  2. I refuse to alter my markup: I will not convert my img tags into div tags, I will not litter my markup with span tags, etc. Not only is this unsightly and cumbersome, it violates semantic correctness. Plus, as a general principle, compatibility hacks/fixes should be kept separate from the "main" code whenever possible.
  3. I want to preserve the behavior of images: An image's alt and title attributes should be respected and preserved. When copying a selection that includes an image, the image must not be lost. The mouse cursor must behave as expected when hovering over image links. When the user right-clicks on the image, all image-related options (save image, etc.) must be present. This is a very common problem; for example, the PNG fix used by Wikipedia violates this principle.
  4. No shenanigans like blank image placeholders: A number of the solutions involved replacing the original image with a blank, transparent GIF placeholder. Aside from my desire to avoid the hassle of having to upload a blank GIF, replacing the image also violates the behavior preservation principle stated above (i.e., users saving the image would be getting the blank placeholder instead).
  5. This should not be a blunt instrument: A good solution should be surgical in its precision. There are cases where I want to apply this fix to every PNG image on the page. There are cases where I want to apply this fix to just a certain set of images. There are cases where I want to apply this fix to just one particular image, or perhaps to every image except for one particular image.

Perhaps I was too exacting. My search for a solution that fit my "simple" requirements was futile, and it was not long before I decided that the best (and probably the only) way that these requirements would be met would be if I rolled my own code.

Designing a Solution

Fortunately, the design of the solution was very straight-forward: my set of requirements pretty much dictated exactly what had to be done. A client-side solution that did not involve deviating from the standard image tag markup meant that the solution had to be "hooked in" using CSS or JavaScript. The requirement that the application be flexible narrowed that down further: I had to use a behavior (how apropos—an IE-specific technology to fix an IE-specific flaw), since they can be attached using CSS. This gives me the flexibility that I want: I could attach this behavior to all img elements, or to elements that match a certain class or ID, or to elements that are descendents of a particular element, etc.

The original image had to be hidden, but the requirement to preserve the use and behavior of the original element effectively meant that I could not move, resize, alter, remove, or change the CSS visibility of the original image; this left only one option: reducing the opacity of the image to zero. But with the opacity set to zero, the AlphaImageLoader could not be used on the image element itself: it had to be used on a separate element with the same size and position as the original image. This element must also appear underneath the original element in the z-index so that the user will interact with the original element instead of the fixup element.

And thus fixiepng.htc was born. Aside from being a tidy and clean solution that met all of my requirements, it also works with images that do not have explicit width and height attributes set (none of the other solutions that I found could do this); this was made possible by my requirement that the original image element be preserved without placeholder images.

Update: My initial version was incomplete because it did not take into account situations where images had borders or padding, were smaller than the line height, or were positioned in unusual ways. I did not initially think to account for these cases because I personally did not run into them in my own usage. But for the sake of completeness, I have released a new version that addresses all of these issues. Borders and padding will now be preserved, images smaller than the line height will no longer appear vertically stretched, and the positioning has been redone so that it will always match that of the original image, even if the original image is positioned in a strange way, gets moved around, etc. fixiepng.htc is still a simple and lightweight solution, weighing in at less than two kilobytes if comments were stripped out—smaller than many of the ones that I had dug up while Googling.

fixiepng.htc: Download, Usage, and Demo

Download: fixiepng.htc (Updated on 2009/04/20)

Usage: <!--[if lt IE 7]><style>img { behavior: url("fixiepng.htc") }</style><![endif]-->

Demos: simple demo, full demo