IE8で透過PNGのフェードが汚れる
以下のような事例を想定します。
こちらの事例はページ読み込み時に、タイル状に並んだ透過PNGがフェードインする要件だったのですが、IE8で表示したときに透過チャンネルの部分が黒く汚れてしまいました。
フェードしているので分かりにくいかもしれませんが、透過部分が黒く汚れてしまっています。
本来は下図のようになっていなければいけません。
当時は時間がなかったため、PNGをJPGにすることで逃げましたが、きちんと解決する方法があったそうです。
このようなバグが発現する条件
主に以下2点です。
- 画像自身をフェードさせている
- 画像にAlphaImageLoaderが指定されていない
解決手順1:親要素をフェードさせる
今回のHTMLの構造は次のようなものでした。
<ul> <li class="item"> <img src="item01.png"/> </li> <li class="item"> <img src="item02.png"/> </li> <li class="item"> <img src="item03.png"/> </li> <li class="item"> <img src="item04.png"/> </li> ...... <li class="item"> <img src="item21.png"/> </li> </ul>
フェードのアニメーションはこちら。
$('.item').find('img').fadeIn();
画像自身ではなく、親要素のliをフェードインするように変更します。
$('.item').fadeIn();
解決手順2:画像にAlphaImageLoaderを指定
IE独自の仕様である、AlphaImageLoaderという画像のアルファチャンネルを有効にするためのフィルタを使用します。 正確には透過画像をサポートするのではなく、「要素」と「要素の背景」の間に画像を配置して疑似的に透過画像をサポートしているように見せるのだとか。 下記記事で詳しく解説されています。
AlphaImageLoaderの書き方は次の通り。
img { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="xxxxx.png", sizingMethod="scale"); }
上記「src="xxxxx.png"」の部分には画像名が入るのですが、HTMLをもう一度ご覧ください。
事例ではたまたま同じ画像を使っていますが、もしすべて異なる画像を用いていたら、スタイルシートに画像分この記述を書かなければいけなくなってしまいます。
それではあまりにも非効率で保守性も下がるので、JSを用いて画像ごとにこのスタイルを直書きします。
$('.item').find('img').each(function(){ var _src = $(this).attr('src'); var _filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + _src + '", sizingMethod="scale")'; $(this).css('filter', _filter); });
これで基本的には問題ないのですが、Google Chromeなどの開発者ツールではスタイルが表示されないため、不安な方はattrメソッドを用いて、style属性の値に設定しても同様の挙動になります。