IEで透過pngにopacity

@nksm さんのつぶやき

IE7+で透過pngに対してopacityを指定した時の汚さはなんとかならんかな。IE6はキレイなんだが・・・。

via http://twitter.com/nksm/status/16611637369

を見つけたので、VMLを使って透過pngにopacityを適用する方法を jsdo.it にあげました。

http://jsdo.it/uupaa/IEAlphaPng_x_Opacity

解説

知識として

  • IE6〜IE8では、filter: AlphaImageLoader(src="**.png") で透過png画像を利用できる
  • IE6〜IE8では、filter: alpha(opacity=0〜100)で 画像の不透明度(opacity)を指定できる
  • filter: は一度にひとつではなく、複数指定できる

があり、これを踏まえて

filter: alpha(opacity=40) progid:DXImageTransform.Microsoft.AlphaImageLoader(src='**.png',sizingMethod=scale); width:400px; height:50px;

とすることで、本来であれば透過png画像にopacityを適用できるはずです。

しかし相手はIE様です。filter: alpha と AlphaImageLoader を併用すると、↓のように画像のAlpha成分がグレーで塗りつぶされた、ジャギ様登場です。

AlphaImageLoader と alpha の順番を変えても結果は同じです。

この問題を解決する方法のひとつに「VMLでopacityを使う」があります。

# 解説用に余分なコードを削っています。

以下のコードを参考にしてください。

<script>
if ([,]!=0) { // IE6 〜 IE8 なら true
  window.onload = function() {
    if (!document.namespaces["v"]) { // VMLネームスペースが定義されていないなら
        // ネームスペース(v) をVMLとして認識させる
        document.namespaces.add("v", "urn:schemas-microsoft-com:vml", "#default#VML");
    }
    // スタイルシートを生成し、<v:rect> と <v:fill> をVMLとして紐付ける
    document.createStyleSheet().cssText = "v\:rect,v\:fill{behavior:url(#default#VML);";
  };
}
</script>
</head><body>
  <!-- 400x50 の透過png画像を opacity:0.4 で表示 -->
  <v:rect id="rect1" style="position: absolute; width: 400px; height: 50px">
    <v:fill id="fill1" type="frame" src="**.png" opacity="0.4" />
  </v:rect>

</body>

結果はこうなります。

opacityのアニメーションも可能です

var opacity = 0;
var timerID;
var node = document.getElementById(...);
function fadein() {
    node.opacity = opacity + "";
    opacity += 0.1;
    if (opacity >= 1 && timerID) {
        clearInterval(timerID), timerID = 0;
    }
}
timerID = setInterval(fadein, 100);

実はJavaScriptいらないんです

jsdo.it では html や head が弄れないため IE 向けの Hack を使うには工夫が必要です。でも実は、HTML と CSS だけで実現可能なんです。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html xmlns:v="urn:schemas-microsoft-com:vml">
<!-- VML need HTML4.01 DOC TYPE -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title></title>
<style>v\:* { behavior: url(#default#VML); }</style>
</head><body>

  <v:rect id="rect1" style="position: absolute; width: 400px; height: 50px; rotation: 0">
    <v:fill id="fill1" type="frame" src="opacity.png" title="" opacity="0.4" />
  </v:rect>

</body></html>

参考になりましたでしょうか?