PNG は、ピクセルごとに透明度 (アルファチャンネル) を持てる画像形式です。半透明の影や、どんな背景にもなじむ角丸の画像を作れるため、Web 制作では早くから使われてきました。ところが Internet Explorer 6 (IE6) は、この半透明の部分を正しく表示できませんでした。その対策として広く使われたのが、IE 独自のフィルターと、DD_belatedPNG のようなスクリプトです。

IE6 で透過 PNG が表示できなかった

IE6 でアルファチャンネルを持つ PNG を表示すると、透明であるはずの部分が灰色っぽい色で塗りつぶされました。透明か不透明かの 2 段階だけの透過 (GIF と同じ考え方の透過) は表示できたので、色数を減らした PNG や GIF で妥協することもよくありました。透過 PNG がそのまま表示できるようになったのは IE7 からです。

AlphaImageLoader フィルター

IE6 にも、透過 PNG を正しく描く仕組みは別にありました。IE 独自の filter プロパティで使う AlphaImageLoader です。

/* IE6 だけに読ませる CSS に書いていた */
.logo {
  background-image: none;
  filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/images/logo.png', sizingMethod='crop');
}

ただし、制約の多い方法でした。

  • background-position や background-repeat が使えないので、画像を並べたり、位置をずらしたりできない
  • src のパスは、CSS ファイルからではなく、HTML のページから見た位置として扱われる
  • フィルターを付けた要素の中のリンクやフォームが、クリックできなくなることがある
  • 対象の画像が多いと、表示が重くなる

DD_belatedPNG の仕組みと、ずれる理由

DD_belatedPNG は IE6 向けのスクリプトで、VML (IE が対応していた、図形を描くための XML の形式) を使って透過 PNG を描き直します。IE の条件付きコメントで IE6 にだけ読み込み、透過 PNG を使っている要素を CSS のセレクターで指定します。

<!--[if IE 6]>
<script src="/js/DD_belatedPNG.js"></script>
<script>
  // 背景や img に透過 PNG を使っている要素を指定する
  DD_belatedPNG.fix(".logo, .shadow, img.png");
</script>
<![endif]-->

AlphaImageLoader と違い、背景の位置の指定や繰り返しも再現できるのが利点でした。その代わり、仕組みに由来する「ずれ」が起きることがありました。

DD_belatedPNG は、元の要素そのものに画像を描くのではなく、VML の要素を別に作り、元の要素と同じ位置・大きさになるように重ねて描きます。つまり、画面に見えている画像は、元の要素とは別の要素です。そのため、次のような場面で、元の要素と描き直した画像の位置が食い違うことがありました。

  • スクリプトが位置を計算したあとで、要素の位置が変わる (画像や文字の読み込み、JavaScript による表示の切り替え、文字の大きさの変更など)
  • position や float、マージンの指定の組み合わせによって、スクリプトが読み取る位置と、実際に表示される位置が食い違う

位置が変わったときにスクリプトが描き直せれば追従しますが、IE6 の再描画のタイミングによっては、それが追いつかないこともありました。当時は、要素や親要素に position: relative や zoom: 1 を指定して IE6 の位置の計算を安定させる、表示を切り替えたあとに描き直させる、といった回避策が試されていました。

今はどうするか

今のブラウザーは、どれも透過 PNG を正しく表示します。AlphaImageLoader も DD_belatedPNG も不要です。条件付きコメントも IE10 で廃止され、今のブラウザーではただのコメントとして無視されます。古いサイトを手入れするときは、これらの指定やスクリプトの読み込みを取り除いてかまいません。

今、画像の形式は次のように選ぶとよいでしょう。

  • PNG: ロゴやスクリーンショット、図など、劣化させたくない画像。透過も使える
  • JPEG: 写真。透過は使えない
  • WebP: 写真にも図にも使え、同じ画質なら PNG や JPEG より小さくなることが多い。透過も使える
  • AVIF: WebP よりさらに小さくできることが多い。透過も使えるが、書き出し (エンコード) に時間がかかる
  • SVG: アイコンやロゴなど、図形で描ける画像。拡大しても粗くならない

WebP と AVIF は今の主要なブラウザーで表示できます。古い環境にも配慮するなら、picture 要素で複数の形式を用意し、ブラウザーに選ばせます。

<picture>
  <source srcset="/images/hero.avif" type="image/avif">
  <source srcset="/images/hero.webp" type="image/webp">
  <img src="/images/hero.png" alt="新しい商品の写真" width="800" height="450">
</picture>

source は上から順に調べられ、ブラウザーが対応している最初の形式が使われます。どれにも対応していなければ img の画像が表示されます。代替テキスト (alt) や width・height は img に書きます。

なお、iframe で読み込んだページでは、親ページで読み込んだ DD_belatedPNG が効かないという問題もありました。理由は iframe の中のページには、親ページのスクリプトや CSS が効かない で説明しています。

まとめ

  • IE6 はアルファチャンネルを持つ PNG の半透明の部分を正しく表示できず、AlphaImageLoader や DD_belatedPNG で補っていた
  • DD_belatedPNG は別の要素 (VML) で画像を重ねて描くため、元の要素の位置が変わると、描き直した画像がずれることがあった
  • 今のブラウザーには不要。古い対策のコードは取り除いてよい
  • 図やスクリーンショットは PNG か SVG、写真は JPEG・WebP・AVIF を目安にし、必要なら picture 要素で出し分ける

参考