CSSハックもIEの独自拡張条件式も使わないIE(6/7/8)のCSS上書きテクニック

Updated / Published

セレクタを上手く活用しているだけの初歩的ながら、あまり知られていない便利なIE(6/7/8)のCSS上書きテクニックです。ハックもIEの独自拡張条件式も使わないこのテクニックを用いれば、次のように良いことづくめです。

  1. 正規のセレクタのみを使用するので、無駄なハックを覚えなくて済む
  2. バグを利用しているハックは将来的にトラブルが発生する可能性があるが、将来的にトラブルも発生しない
  3. ハックは正常なブラウザの解析では構文エラーとなるが、正規のセレクタのみの使用なのでエラーなくスムーズに解析できる
  4. IEの独自拡張条件式である<!--[if IE]>〜<![endif]-->を使ってIE専用のCSSファイルを作って管理しなくても、同一CSSファイル内で手軽に上書きが済ませられる

まず、下記のようなHTMLがあると仮定します。なんてことない、よくあるソースコードです。

<html lang="ja">
...
<body>
<div id="logo">
<img src="xx.png">
</div>
....
</body>
</html>

このソースコードを例にして、#logo 内にある img に指定した左マージンによる表示位置がIE6とIE7とIE8とその他モダンブラウザ(IE9以降, Safari, Chrome, Firefox, Opera)とでそれぞれ微妙にズレてしまうとしましょう。そのため、それぞれに異なる数値を指定してやる必要がでてくるわけですが、次のように上手くセレクタを駆使することで対応するブラウザにのみ順番に上手く上書きさせることができます。

/* IE6のみに適用される */
#logo img { margin-left:-3px; }
/* IE7のみに適用される */
#logo > img { margin-left:-2px; }
/* IE8のみに適用される */
html:lang(ja) #logo > img { margin-left:-1px; }
/* IE9以降, safari, Chrome, Firefox, Operaのモダンブラウザに適用される */
html:root #logo > img { margin-left:0; }

一つずつ順を追って解説していきましょう。

  • まず、#logo img はどのブラウザも解釈できる子孫セレクタの指定です。
  • 次の #logo > img は子セレクタによる指定です。IEで子セレクタはIE7からサポートしています。つまり、ここで指定されている margin-left:-2px; の指定は IE6 には無効です。
  • 3番目の html:lang(ja) #logo > img は、:lang() 擬似クラスを用いています。html要素には通例その文書の言語を示しているはずでしょうから、日本語のドキュメントであれば html:lang(ja) の形で使用します。英語のドキュメントであれば html:lang(en) と指定します。IEでこの :lang() 擬似クラスをサポートしているのはIE8からです。つまり、ここで指定されている margin-left:-1px; の指定は IE6 と IE7 には無効です。
  • 最後の html:root #logo > img は、CSS3 で追加されたセレクタのひとつで、文書のルート要素に使える構造擬似クラスです。HTML文書であれば、ルート要素(最大の親要素)はhtml要素なので、html:root の形で使用します。また、上書きのルールとして、html:lang(ja) #logo > img より後で指定することがポイントです。詳細度が同じ場合は、当然、後に書いたものが上書きされるからです。そして、IEでこの文書のルート要素をセレクタにできる構造擬似クラスをサポートしているのはIE9からです。つまり、ここで指定されている margin-left:0; の指定は IE6, IE7, IE8 には無効です。

以上の結果から、IE6 に有効なのは一番最初の #logo img { margin-left:-3px; } のみなので、この指定がそのまま通ります。

次に、IE7 では、先の #logo img { margin-left:-3px; } を上書きする #logo > img { margin-left:-2px; } の指定が通ります。
そして、IE8 では、さらに #logo > img { margin-left:-2px; } を上書きする html:lang(ja) #logo > img { margin-left:-1px; } の指定が通ります。

他のモダンブラウザ(IE9以降, Safari, Chrome, Firefox, Opera)には、さらに html:lang(ja) #logo > img { margin-left:-1px; } を上書きする html:root #logo > img { margin-left:0; } が通るというわけで、ハックもIEの独自拡張条件式も使うことなく、これで簡潔にIE6/IE7/IE8をそれぞれ上書きすることができてしまうわけです。

実際の使用ケースでは、IE6とIE7がかなりのヤンチャっぷりを発揮して、IE8からはそれなりに言う事を利いてくれるので、IE6とIE7とその他ブラウザ(IE8以降とSafari, Chrome, Firefox, Opera)で別けてあげるケースが多いかと思いますが、それなら

/* IE6のみに適用される */
#logo img { margin-left:-3px; }
/* IE7のみに適用される */
#logo > img { margin-left:-2px; }
/* IE8以降, safari, Chrome, Firefox, Operaに適用される */
html:lang(ja) #logo > img { margin-left:-1px; }

と書き分ければいいわけです。