読者です 読者をやめる 読者になる 読者になる

orangain flavor

じっくりコトコト煮込んだみかん2。知らないことを知りたい。

DD_belatedPNGを使ってる場合でもスマートロールオーバーが動くようにする

javascript

はじめに

DD_belatedPNGを利用すると、IE6でPNGファイルを透過させることが出来ます。
DD_belatedPNGはITキヲスク | IE6で透過pngを表示させるオススメscript、「DD_belatedPNG.js」で解説されているように、簡単にそして高速に透過PNGを表示できるという特徴があります。
しかし、ITキヲスク | IE6用透過png対応策、DD_belatedPNGの使用法と注意点で解説されていますが、次のような問題点があります。

ここで、img要素に使用する際のいくつかの注意点を。

ただimg要素にpng画像を使うだけなら、上記で何の問題もありません。

しかし、png画像のimg要素にロールオーバーを設定したい場合、少し注意とコツが必要なんです。

たとえば、png画像のimg要素を<a>要素で囲んでリンクボタンとして、img要素をロールオーバーさせたい場合、img要素に onmouseover=なんちゃら って指定しても、動きません。

http://smkn.xsrv.jp/blog/2009/04/postscript_dd_belatedpng_js/

このため、例えばソースがシンプルなJSによるロールオーバー - CSS HappyLifeのようなスクリプトは上手く動きません。そこで、DD_belatedPNGを使った状態でもスマートロールオーバーを実現してやろうというのが本記事の趣旨です。

なぜ動かないのか?

なぜ動かないかなんて興味ないから、動くスクリプトが欲しいという方はこの節は無視して次の節へどうぞ。

そもそもPNGが透過されないはずのIE6で、DD_belatedPNGがどのようにしてPNGを透過させているのかを見ていきます。まあ端的に言えば、VMLというものを使って実現しているのですが。(VMLの説明はとほほのVML入門がわかりやすいと思います。)

具体的には、元々あった次のような<img>要素を

<img src="http://〜.png">

DD_belatedPNGは次のように変更します。*1

<DD_belatedPNG:shape><!--color: 背景色用-->
    <DD_belatedPNG:fill/>
</DD_belatedPNG:shape>
<DD_belatedPNG:shape><!--image: 画像用-->
    <DD_belatedPNG:fill src="http://〜.png"/>
</DD_belatedPNG:shape>
<img src="http://〜.png" style="visibility: hidden"/>

<img>要素を非表示にして、VMLの要素を前に挿入することで、今まで<img>があったところにVMLを使って画像が表示されるようになります。普通の<img>要素の描画ではPNGを透過させられないのに対し、VMLの描画では透過させられるということを利用しているわけですね。見つけた人はすごい!

ここで、JSが動かない理由がわかってきたでしょうか。<img>要素に対してイベントハンドラを設定しても、<img>要素は非表示になっており、見えているのはVMLで表示されている画像なのです。これでは<img>要素に設定したイベントハンドラは動作しませんね。

逆に言えば、VMLで表示されている要素に対してイベントハンドラを設定すれば動くことになります。

スマートロールオーバーを実現する

それではスマートロールオーバーを実現してみましょう。普通DD_belatedPNGを使う際には、次のようにしますが

<script type="text/javascript src="〜/DD_belatedPNG_0.0.8a-min.js"></script>
<script type="text/javascript">
    DD_belatedPNG.fix('img, .png_bg');
</script>

これを次のように変更します。

<script type="text/javascript src="〜/DD_belatedPNG_0.0.8a-min.js"></script>
<script type="text/javascript">
    var oldFixPng = DD_belatedPNG.fixPng;
    DD_belatedPNG.fixPng = function (el) {
        oldFixPng(el);
        if (el.vml && el.vml.image.fill.getAttribute("src").match(/_off\./)) {
            el.vml.image.shape.attachEvent('onmouseenter', function() {
                var image = el.vml.image.fill;
                image.setAttribute("src", image.getAttribute("src").replace("_off.", "_on."));
            });
            el.vml.image.shape.attachEvent('onmouseleave', function() {
                var image = el.vml.image.fill;
                image.setAttribute("src", image.getAttribute("src").replace("_on.", "_off."));
            });
        }
    };
    DD_belatedPNG.fix('img, .png_bg');
</script>

こうすることで、IE6でDD_belatedPNGを使ってる場合にもスマートロールオーバーが動くようになります。DD_belatedPNGが適用されている<img>タグだけ別の処理をしているという方が正確ですね。

結論

IE6なんてサポートしない方が身のためだし世界のためになると思います。IE6でだけロールオーバーしなかったとしてもきっと誰も困らないでしょう。

*1:これはあくまで簡略化したものです。[http://www.tohoho-web.com/wwwvml.htm:title]では<v:shape>だったものが、ここでは[]<DD_belatedPNG:shape>[]になっていることに注意して下さい。コロンの前は設定に合わせて任意の名前を使うことが出来ます。