ブラウザによって異なる画像を表示する

世間では史上空前の参考文献記述ブームだそうですが、そんなことは気にせずにとりあえずhoshikuzuさんの出題された『詰めHTML』で遊んでみました。

ちょっと思い出したのでクイズを書いてみます。

以下の条件で、IEでは、imgie.gif、 Firefoxでは、imgfx.gif、その他多くののブラウザでは、imgother.gif ノミを表示するHTMLを作ってください。

  1. JavaScriptなどのスクリプトは使わない
  2. CSSを通じてハックしない
  3. HTMLの書き方のみで勝負するが、validでなくても良い

書いてみたのはこれ。

IEだとモヒカンの人が、Firefoxだと今夜わかる人が、それ以外のブラウザだと危険文字メタ文字の中の人が表示されると思います。「それ以外のブラウザ」はWindows 上の Opera で試しましたので、Opera以外のブラウザだとどうなるかよくわかりません。Safariだと Firefox と同様の扱いになるとの情報をもらいました(参考文献:私信)。
以下、簡単に解説と参考文献。

<meta http-equiv="Content-Type" content="text/html;charset=jis">

と書くことで、Firefoxでは ISO-2022-JP と解釈させています。IEは「jis」を理解しないため、デフォルトのcharsetである Shift_JIS であると解釈します。Operaでも「jis」を解釈しないようですが、後続のエスケープシーケンスをもとにISO-2022-JPと判断しているようでした*1。次に、<img>にて

<img (0x1B)(0x28)(0x42)(0x08)src="..." ...
と書きます。0x1B 0x28 0x42 というバイト列は、HTMLをISO-2022-JPと解釈しているFirefoxOperaでは、US-ASCIIへの切り替えのエスケープシーケンスということで意味を持ちません(無視されます)。HTMLをShift_JISと解釈しているIEでは "(0x1B)(0x28)(0x42)(0x08)src" の7バイトが属性の名称となりますので、src属性はまだ与えられていない状態となります。エスケープシーケンスに続く 0x08 は、Firefox では空白文字と同じ扱いになるバイト値です。よって、Firefox のみに有効な src 属性を書くことができました。
さらに続けて
<img (0x1B)(0x28)(0x42)(0x08)src="..." (0x1B)(0x28)(0x42)src="..."
とします。HTMLをISO-2022-JPと解釈しているFirefoxOperaでは上記の説明同様、0x1B 0x28 0x42を無視し、src属性が有効となりますが、Firefoxではすでに src 属性が与えられていますので、この後続のsrc属性は無視されます。これにより、Operaでのみ有効な src 属性を書くことができました。
残るIEは普通に
<img (0x1B)(0x28)(0x42)(0x08)src="..." (0x1B)(0x28)(0x42)src="..." src="..."
とすることで、src属性が有効になりました。
今回はわざわざ回りくどい方法で文字コードネタを含ませてみましたが、0x00のような、ブラウザによって解釈が異なるような文字の違いを利用すればもっとシンプルに書くこともできます*2

参考文献
http://d.hatena.ne.jp/hasegawayosuke/20061105/p1
http://d.hatena.ne.jp/hasegawayosuke/20070313/p1
http://d.hatena.ne.jp/hasegawayosuke/20070717/p1



(2007/09/28追記) 最近は801方面での活躍が華々しいという噂の竹迫さんによる例。アッー!

*1:Operaでの確認はあんまり深くやっていないので要再調査

*2:Safariは2と3で0x00の扱いに差があるそうです。参考文献:私信