How to solve/hack fading semi-transparent PNG bug in IE8?

As you know, IE6 has bug that can't display semi-transparent PNG file without using non-standard style like filter. In IE7, this problem is fixed. But It still has some bug about PNG file. It can't correctly display fading semi-transparent PNG file. You can clearly see it when you use show/hide function in jQuery with semi-transparent PNG file. The background of image is displayed with non-transparent black color.

Do you have any idea for solve this question by using jQuery.

Update

Let's see my testing

alt text http://rabu4g.bay.livefilestore.com/y1pGVXLwPdkxudYLmIdnMpWTP_9up-8isxbPKX945Ui4ITnYWnR0msaa2NmUF-qJ-Q4a2AAGaiGHwaFSgR1HeplDIO0bWbyRODI/bug.png

As you see, IE8 always incorrectly displays PNG-24 image. Moreover, IE8 still correctly display PNG-8 image when I fade(jQuery.fadeOut function) it only. But It incorrectly display PNG-8 image when I fade & resize(jQuery.hide function) at the same time.

PS. You can download my testing source code from here.

Thanks,


Hey, I don't know if you're still looking for an answer. A couple of days ago I had the same issue animating a div with a PNG image inside. I tried many solutions and the only one that worked fine is one I coded myself.

The issue seems to be IE lacking opacity support and proper PNG support, so it breaks PNG display after applying an opacity effect (I believe animation frameworks rely on the propietary MSIE filter "AlphaImageLoader" for opacity effect on IE). The curious thing (to me that still don't understand very well) is that this issue can be solved using the same filter to load the image before the animation.

I wrote a simple javascript that applies the filter to every image with .PNG extension. My animations run fine on IE with it.

I copy the code below. I'ts framework independent (it's pure JavaScript), but you have to put it inside your framework's DOM ready event (or use domready.js, like I did).

var i;
for (i in document.images) {
    if (document.images[i].src) {
        var imgSrc = document.images[i].src;
        if (imgSrc.substr(imgSrc.length-4) === '.png' || imgSrc.substr(imgSrc.length-4) === '.PNG') {
            document.images[i].style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true',sizingMethod='crop',src='" + imgSrc + "')";
        }
    }
}

Please let me know if worked fine for you and if animation runned smooth. Kind regards!


HTML

   <img src="image.png" class="iefix" width="16" height="16" />

in CSS

.iefix
{
 /* IE hack */
  background:none\9; /* Targets IE only */
  filter:progid:DXImageTransform.Microsoft.AlphaImageLoader();
}

easy, fast and nice :)


The root cause of the problem appears to be Micrsoft IE's poor support for the PNG alpha-transparency (in any version of IE). IE6 is the worst offender by far, rendering alpha-transparent pixels as a pale blue color. IE7 and IE8 handle PNG alpha-transparency, but can't handle changing the opacity of an alpha-transparent pixel in the PNG – they render as black instead of transparent.

My own fixes for this depend on the situation. Here are some approaches:

  1. Just use a GIF. GIFs won't appear as smooth (because of limited color depth), but the pixels are fully transparent.
  2. Use the IE PNG fix available here: http://git.twinhelix.com/cgit/iepngfix/ -- open up index.html and read the comments.
  3. Animate motion, but don't animate opacity of PNG images.
  4. Conditionally do any or all of the above using either JavaScript tests, conditional comments, or the MSIE-only "behavior" extension to CSS. Here's how any of that might work:

Conditional comments:

<!-- in index.html, in the <head>: -->
<!--[if IE 6]>
<link rel="stylesheet" src="css/ie6only.css" />
<![endif]-->

In the css:

/* ie6only.css */
img { behavior: url("js/iepngfix.htc"); }

Via JavaScript detection:

<script defer type="text/javascript">
if(navigator.appName == "Microsoft Internet Explorer")
{ /* Do IE-specific stuff here */ }
else
{ /* Non-IE-compatible stuff here */ }
</script>

The iepngfix.htc behavior works by replacing the PNG with a blank image (blank.gif) and then using Microsoft's DXImageTransform routines to load the PNG as a filter on the blank image. There are other PNG fixes out there which work by wrapping things in divs or spans, but those will often break your layout, so I avoid them.

Hope this helps.


I've managed a fix to this issue for IE 6/7/8.

Roughly looks like this:

<div class="wrapper">
  <div class="image"></div>
</div>

...

/* I had to explicitly specify the width/height by pixel */
.wrapper
{
  width:100px;
  height:100px;
}

.image
{
  width:100%;
  height:100%;
  background:transparent url('image.png') no-repeat;

  /* IE hack */
  background:none\9; /* Targets IE only */
  filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src="image.png", sizingMethod="crop");
}

...

$(".wrapper").fadeOut('slow');

Note that the "filter" attribute implicitly targets IE only.


I used this function to preload images into gallery carousel. It's based on Alejandro García Iglesias's answer above. It got rid of the "black halo" in IE 6 & 8.

function preloadImages(id) {
    var c = new Array();
    $(id+' img').each( function(j) {
        c[j] = new Image();
        c[j].src = this.src;

        if ( $.browser.msie ) {
            this.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true',sizingMethod='image',src='"+ this.src +"')"; 
        }
    });

}

Call like this:

preloadImages('#Stage');