PNG in Windows IE: Info & Links
Home | The Problem | The Solution | How To Use | More InfoThis page contains more information for the curious or those who wish to amend the script for special needs.
- Pros & Cons
- Troubleshooting
- Workings
- Variations
- Rollovers
- Imagemaps & Input Images
- Other Solutions
- Credits
Pros & Cons
Pros:
- Ignored as a comment in other browsers - it's only run by Windows IE.
- Works with (X)HTML Strict & Transitional Doctypes
- Does not break W3C validation
- Lightweight and very easily deployed
- Works with existing in-line or external CSS rules based on class or ID selectors
- Works with old-style img align="left" or align="right" attributes
- Runs after any existing Body Onload code
- Works with imagemaps and input images using a special version
Cons:
- Doesn't work in IE versions earlier than 5.5 - the AlphaImageLoader filter wasn't introduced until version 5.5. There is no cure for earlier versions.
- Requires JavaScript to be enabled - the estimations for how many people choose not to use JS vary wildly. See note [1]
- CSS backround PNGs not supported - experimentation revealed I could traverse the Stylesheets collection and use the AlphaImageLoader trick to replace all background-image attributes containing PNGs, but then background-repeat would not work, and anchors placed over non-transparent parts of the image were not clickable :-(
- CSS rules for the PNG images based on the img selector are lost, but this is easily rectified by adding a class selector to your img rule such that img{..} becomes img,.png{..} - then add the attribute class="png" to each of your PNGs.
[1] The figures commonly quoted for the percentage of users with no JS are usually those supplied by The Counter. However, the variances in their statistics are so large as to suggest their system is rather flawed. They reckoned 13% of users had no JS in December 2003. This had dropped to 4% by January 2004! My real-world experience of many users in many businesses and homes is that very close to zero users turn off JS, but your world view and target audience may of course be different.
Troubleshooting
Most of the feedback I receive indicates that the script works fine "out of the box". However, some issues appear often enough for a pattern to emerge. As I receive feedback, I will post problems and solutions here:
- Image slightly distorted or not quite fitting to boundaries. This can usually be solved by searching the code and changing sizingMethod='scale' to sizingMethod='image' or sizingMethod='crop'. I chose 'scale' as this option respects any styled borders on the images. The other options do not, but may render smaller images better
- Page jumps by a few pixels. In certain circumstances, the script can make the page 'jump' upwards, by a few pixels when it runs. This is due to spurious carriage returns in the HTML. In MSIE, these can leave a small space underneath the image, which the script removes once it runs. This has the effect of making the entire page below the PNG 'jump' slightly. The fix is to remove any errant carriage returns from your code.
How It Works
I left the code uncommented for the sake of brevity, but the explanation below should suffice should you wish to hack it up or improve it.
If used inline, the code runs after any existing onLoad code has completed. If used as an include file, the DEFER keyword ensures it is run when the DOM has loaded, but before the images are rendered. It converts each PNG image into a span with the PNG's width and height attributes. The IE 5.5+ AlphaImageLoader filter is then applied to fill each new span with the original image. It is this filter which allows PNG transparency to work correctly - see KB 294714 for more details. Alt attributes are converted to titles for mouse hover text. Any existing in-line CSS declarations plus title, ID & class attributes are transferred to the new spans.
Each new span has the declaration display:inline-block added - this enables the fix to work with "Standards mode" IE6 Doctypes. Finally, each replaced PNG is checked to see if it has the (deprecated) align="left" or align="right" attribute. If so, an appropriate CSS float declaration is added in-line in order to replicate the original alignment. Also, if the original image was used within an anchor as a link, then a hand cursor is applied to the new span in order to replicate the original link image cursor.
Variations
I was asked to amend the thing for pages with large numbers of images in order to reduce the initial flash of ugly border sometimes seen before the code does its job. I did not include these ideas in the original method as they break the "copy & paste" model somewhat, but they may nonetheless be of use:
(1) CSS Hide
Use a CSS class to hide your PNGs by setting visibility:hidden, then have the JS reveal them again after the transformation by adding visibility:visible straight after sizingMethod='scale'); so that the whole line looks like:
strNewHTML += "(src=\'" + img.src + "\', sizingMethod='scale'); visibility:visible\"></span>"
Caveat: if the user has CSS enabled and JS disabled, then the images will remain invisible!
(2) JS code on individual PNGs
This method does no checking for deprecated img align="left" or align="right" attributes. It also breaks the non-invasive JS principal somewhat in that it is specifically called by selected PNG images on load in all JS-supporting browsers. However, while the function is called in all browsers, it only actually does something in IE 5.5 and 6.
var arVersion = navigator.appVersion.split("MSIE")
var version = parseFloat(arVersion[1])
function fixPNG(myImage)
{
if ((version >= 5.5) && (version < 7) && (document.body.filters))
{
var imgID = (myImage.id) ? "id='" + myImage.id + "' " : ""
var imgClass = (myImage.className) ? "class='" + myImage.className + "' " : ""
var imgTitle = (myImage.title) ?
"title='" + myImage.title + "' " : "title='" + myImage.alt + "' "
var imgStyle = "display:inline-block;" + myImage.style.cssText
var strNewHTML = "<span " + imgID + imgClass + imgTitle
+ " style=\"" + "width:" + myImage.width
+ "px; height:" + myImage.height
+ "px;" + imgStyle + ";"
+ "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
+ "(src=\'" + myImage.src + "\', sizingMethod='scale');\"></span>"
myImage.outerHTML = strNewHTML
}
}
To implement this only on specific PNGs, add the following to each PNG image you wish to transform:
<img src="xyz.png" alt="foo" width="10" height="20" onload="fixPNG(this)">
NB: You must have height and width attributes specified.
Rollovers
Mouseover tricks are usually used to swap images. The standard PNG fix function will break these, as it converts PNG images into spans. There is a way around this, depending on your requirements. If you need this functionality, check out the mouseover demo page.
Imagemaps & Input Images
Imagemaps and images used as form inputs do not work with the regular pngfix, but there is a special version you can use which requires an additional single pixel image in order to work. If you need this functionality, check out the imagemap & input images page.
Other Solutions
There are many other solutions to this problem - you may wish to check them out to see if they better fit your needs:
- PNG Behavior - uses .htc file & 1px GIF
- Youngpup - IE behavior & 1px GIF
- Lloyd Dalton - CSS only, no JS
Fred Boyle emailed me with a Flash solution. He says you can "simply import the PNG into Flash and use the generated Flash movie using the WMODE parameter set to "transparent". This works wonderfully!" . I am not a user of Flash so cannot comment on this approach but hopefully some may find it helpful.
Credits
This hack was inspired by a Zeldman article by Michael Lovitt, who details the core trickery. I simply built on Michael's ideas. Thanks are also due to Kerry Watson who spurred me on to get more features working and helped with testing. Kerry runs the excellent Webcolours PNG advocacy site.
I'm also very grateful to the following:
- www.walterzorn.com for the JS drag library code
- Joern Huxhorn and Jelle Veraa who suggested some methods to get imagemaps working.
- John Shanks for catching a bug - now fixed - in the individual PNG fix code above.
- Henrik Nyh for suggesting using the defer keyword instead of onload as per Dean Edwards' blog
- James Cridland for reporting the carriage return rendering bug described in the troubleshooting section.