IE8と透過pngとJavascriptで泣いた話

IE8と透過pngとJavascriptで泣いた話

2012年9月10日

IE6、7がほぼ駆逐されてきましたが、IE8もなかなかくせ者だったというお話をつらつら書いておこうと思います。
主にJavaScriptで、起きた話なんですけども。IE9はわりと良い感じなんですけどねー…。

[Ad]

透過pngでOpactyを変更すると真っ黒に

先方からの依頼で、リンクテキストにマウスを乗せたら、透過pngで作った吹き出しをfadeInで表示し、その中に任意の文字列を表示させる、というのをJavaScriptでやることになりました。
そんなに難しい話でもないですし、よくある依頼ですよね。

JavaScript、CSSなどは以下のような感じ

CSS

/* CSS */
.balloon{
     height:200px;
     position:relative;
}
.balloon a span{
     display:none;
     width:185px;
     height:80px;
     position:absolute;
     top:20px;
     left:30px;
     background-image: url(img/bg_balloon.png);
     background-repeat: no-repeat;
     background-position: left top;
     padding:45px 0 0;
     text-align:center;
     color:#333;
}

JavaScript

// JavaScript
     $('#balloon1 a').mouseover(function(){
          $('#balloon1 a span').fadeIn('slow');
     });
     $('#balloon1 a').mouseleave(function(){
          $('#balloon1 a span').fadeOut('slow');
     });

HTML

<!-- HTML -->
<div id="balloon1" class="balloon">
<p><a href="javascript:void(0)">ここにマウスオーバー<span>吹き出しの内容は<br>ここに書く</span></a></p>
</div>

サンプル1

IE8で見てみると、一瞬妙な黒枠が出てしまうのです。
ちなみに私はWin7を使っていて、IE9の開発者ツールでIE8にした状態では確認されませんでしたが、XPのIE8だと起きました。
(IETesterでは再現されました)
調べてみると、同様の現象で困っている人が多数。

解決策

結局この時は時間もなく、先方からの変更依頼でfadeIn/Outの処理は要らなくなったので、fadeIn/Outをしない、ということで解決?しました。
時間が出来てから調べてみると、以下の記事に辿り着きました。

ie8でもやっぱりpngfix – markup おぼえがき
AlphaImageLoaderフィルターとIEの振る舞い|POPS WEB

上記を参考に色々試して、解決したサンプルが以下。

CSS

<style type="text/css">
.balloon{
     height:200px;
     position:relative;
}
.balloon a span{
     display:none;
     width:185px;
     height:80px;
     position:absolute;
     top:20px;
     left:30px;
     background-image: url(img/bg_balloon.png);
     background-repeat: no-repeat;
     background-position: left top;
     padding:45px 0 0;
     text-align:center;
     color:#333;
}
</style>
<!--[if IE 8]>
<style type="text/css">
.balloon a span.pngfix {
     background: transparent url("img/bg_balloon.png") no-repeat left top;
     filter :progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img/bg_balloon.png',sizingMethod='scale');
     background-image: none;
}
</style>
<![endif]-->

JavaScript

// JavaScript
     $('#balloon2 a').mouseover(function(){
          $('#balloon2 a span').fadeIn('slow');
     });
     $('#balloon2 a').mouseleave(function(){
          $('#balloon2 a span').fadeOut('slow');
     });

HTML

<!-- HTML -->
<div id="balloon2" class="balloon">
<p><a href="javascript:void(0)">ここにマウスオーバー<span class="pngfix">吹き出しの内容は<br>ここに書く</span></a></p>
</div>

サンプル2

jquery.belatedPNG.jsも試してみたんですが、背景画像が消えてしまう、という謎現象にぶちあたりました。
CSS側を上手い事ハックで解決出来ないかなーと思ったんですが、中途半端に黒枠が消えるというなんともいえない結果になり、<!–[if IE 8]>でIE8のみ適用するCSSにfilterを使う、というちょっと強引ですがしょうがない感じで解決しました。

透過pngだと妙なキャッシュ?が起こる話

先方からの依頼で、数字がぱたぱたとランダムに変わるアニメーションをした後、任意の数字を表示させる、というのをJavaScriptでやることになりました。
数字は画像で。数字画像の背景がグラデだったり、同じ画像を別の場所でも使う、ということもあり、透過pngで数字画像0〜9を用意。

JavaScriptは以下のような感じでさらっと組めたんですが

// JavaScript
$(function() {
     $('#setBtn1').click(function(){
          var setNum = $('#numSet1').val();
          numAnime(setNum,'numArea1');
     });
});

function numAnime(_num,_numID){
     var numStr = _num;
     numID = _numID;
     numhtml = '';
     $('#'+numID).html(numhtml);
     numList = new Array();
     for(i=0; i<numStr.length; i++){
          numListStr = numStr.substring(i,i+1);
          numList.push(numListStr);
     }

     // 画像をセット
     numhtml = '<img src="img/num0.png" width="30" height="50" class="numId1">';
     numhtml += '<img src="img/num0.png" width="30" height="50" class="numId2">';
     numhtml += '<img src="img/num0.png" width="30" height="50" class="numId3">';
     $('#'+numID).prepend(numhtml);

     // アニメーションの実行
     animeSpeed = 50;
          Timer1 = setInterval("cntAnime('1')", animeSpeed);
          Timer2 = setInterval("cntAnime('2')", animeSpeed);
          Timer3 = setInterval("cntAnime('3')", animeSpeed);

     // アニメーションの停止
     stopSpeed = 100;
          setTimeout("cntAnimeStop(1,numList)",stopSpeed*5);
          setTimeout("cntAnimeStop(2,numList)",stopSpeed*6);
          setTimeout("cntAnimeStop(3,numList)",stopSpeed*7);

     return;
}

// アニメーション実行
function cntAnime(_imgNum){
     var Rnd = Math.floor(Math.random()*10);
     var imgSrc = 'img/num'+Rnd+'.png';
     $('#'+numID+' img.numId'+_imgNum).attr({'src': imgSrc});
     return;
}

// アニメーション停止
function cntAnimeStop(num,_numList){
     if(num == 1){clearInterval(Timer1);
     }else if(num == 2){clearInterval(Timer2);
     }else if(num == 3){clearInterval(Timer3);
     }
     var k = num-1;
     var imgSrcSet = 'img/num'+_numList[k]+'.png';
     $('#'+numID+' img.numId'+num).attr({'src': imgSrcSet});
     return;
}

サンプル3

ブラウザ別で動きを確認していると、IE8でだけ妙な挙動をするのです。
アニメーションの後任意の数字で止まるはずが、IE8でだけ時々デタラメな数字で止まってしまうのです。
相変わらずWin7/IE9の開発者ツールでIE8にした状態では確認されませんでしたが、XPのIE8だと起きました。
(IETesterでも再現されないので、XP+IE8固有のバグでしょうか…?)
特に変わった事もしていないし、色々と試してみましたが、原因が分からず。
ぱたぱたとランダムさせるスピードを落として確認してみましたが、最後の任意の数字になる手前でそのまま動きが終わる、という謎現象。
色々調べましたが、IE8で透過PNGを使用して動きを付けると挙動がおかしい、ということぐらいしか分からず。

解決策

PNGがダメなら、GIFにすればいいじゃない

最終的に、GIFにする事で解決しましたorz
結局、XPにある透過させる為の部分が上手く動作できてないんじゃないかなーという結論。
上記のような動きを作る場合は、IE8と透過PNGに気をつけてください。

画像がGIFになっただけのサンプル4はこちら

IEにはホントに泣かされました

最初の現象はググれば同じような目に遭ってる人がいたのでよかったんですが、2番目の現象については前例というか同じような人がいなくて、何が原因なのかさっぱりで泣きました。
サンプルで挙げた箇所は実際に作ったScript全体の一部で、それ以外の場所に原因があるのではないか?というのもあって、一日潰れましたよ_(:3 」∠ )_

このバグ潰ししてる最中に以前の記事「JavaScriptでCookieを扱いたい時のメモ」で挙げた「IEで、path=/hoge/hoge.html という指定をしようとするとCookieそのものがセットできない」というバグにも気付きまして、IEなんて滅んでしまえ!と何度吠えたことでしょう。

IEがあるかぎり、透過pngを使う場合は色々考えなきゃいけないってのも、悲しいですね @;ェ;@