Apr 25 2013

IEのCSS対策総まとめ 小さなズレ・フロートの不具合・PNGの透過など

ウェブサイトをつくるうえで避けて通れないのがIEのバグとの戦いです。特にCSSのバグは凄まじく、何も知らずにIE6で表示確認なんかすると、その崩壊したサマにしこたま絶望感を味わうことになります。

IEと対峙するためにまず必要なのは、各バージョンごとの大まかな特徴を理解し、その付き合いかたに慣れることです。IE9以降は別としても「なんとなくやったけど何も問題なかった」なんてことは十中八九ありません。今回はその付き合いかたをまとめようと思います。

1. doctype宣言

IE6以降、doctype宣言の書き方によってCSSの解釈モードを変更するDOCTYPEスイッチという機能があります。解釈モードは次のふたつです。

  1. 標準準拠モード:CSSの解釈を、W3Cが定めた仕様にあわせるモード
  2. 後方互換モード:CSSの解釈を、バージョン6未満のIEにあわせるモード

これらの最大の違いはボックスモデルの解釈です。CSS3にbox-sizingというプロパティがありますが、標準準拠モードの場合は、box-sizingでいうcontent-boxとして動作します。一方、後方互換モードの場合はborder-boxとして動作します。レスポンシブ・ウェブデザインによってグリッドレイアウトが注目され、それに伴いborder-boxも使われるようにはなっていますが、box-sizingプロパティをIEがサポートしたのはバージョン8からです。

doctype宣言についての詳細は割愛しますが、一つだけ注意があります。IE6には、doctype宣言の前に1バイトでも文字があると後方互換モードになってしまうバグがあります。XHTMLでマークアップする場合、XML宣言があるだけで後方互換モードになります。また、文字コードとしてUTF-8など、いわゆるユニコードを採用する場合にも、テキストエディタによっては文書の先頭にBOM(Byte Order Mark)と呼ばれる3バイトの情報を付加することがあり、これも後方互換モードの引き金になります。IE6をサポートする場合は注意してください。

XHTMLの場合はdoctype宣言は様々なバリエーションがありますが、HTML5の場合、標準的なdoctype宣言を書けば、IEは標準準拠モードで動作します。

2. hasLayout

IEにおけるCSSのバグで特に悩まされるのがレイアウトのズレです。特にバージョン7までは凄まじい勢いでズレますが、そのほとんどがIEの独自実装であるhasLayoutというCSSプロパティに起因しています。

hasLayoutをオンの状態にすればほとんどのレイアウトのズレは修正できるのですが、hasLayoutは読み込み専用のプロパティなので直接指定することができません。

じゃあどうするかっていうと、他の特定のプロパティを指定することで、hasLayoutの値を間接的にオンにすることができるんです。widthやheightなど、いくつかのプロパティがありますが、最も副作用が少なく使いやすいのはzoomプロパティです。おかしいなと思ったら、まずはzoomを指定してみましょう。

.selector {
	*zoom: 100%;
}

zoomプロパティの前に付いているアスタリスクはCSSのハックで、これによりバージョン7以下のIEだけがzoomを解釈するようになります。詳しくはIEのCSSハックについての記事をご覧ください。

3. floatとダブルマージン

IE6のバグで、floatで指定したのと同じ方向にmarginを指定すると、marginが指定した数値の倍の値になってしまうという、ダブルマージンと呼ばれるものがあります。例えば、次の例の場合、IE6での実際の左マージンは20pxになってしまいます。

.selector {
	float: left;
	margin-left: 10px;
}

このバグを回避するためには、display:inline;を追加してやります。

.selector {
	float: left;
	margin-left: 10px;
	*display: inline;
}

ハックを使ってプロパティの影響する範囲をIEに限定しなくとも、CSSの仕様的には問題ないのですが、特定のバグに対する意図的な処置という印としてハックを使っています。気に入らないかたは外しても問題ありません。

4. clearfix

要素をフロートした場合、最後にそれを解除してあげないと、仕様通り、親要素の高さが0になってしまいます。なのでフロートを解除する必要があります。

<div>
	<div style="float: left;">Foo</div>
	<div style="float: left;">Bar</div>
	<div style="float: right;">Buz</div>
	<div style="clear: both;"></div>
</div>

ただ、いつもこれが出来るわけではありません。例えば、リスト要素の場合はフロートを解除するために先の例のようなマークアップは出来ないわけです。なので、通常は次のようにしてフロートを解除します。

<ul class="sample">
	<li class="menu">Foo</li>
	<li class="menu">Bar</li>
	<li class="menu">Buz</li>
</ul>
.menu {
	float: left;
}
.sample:after {
	content: '';
	display: block;
	clear: both;
}

このテクニックは一般的にclearfixと呼ばれていますが、IEがbefore・after擬似要素をサポートしているのはバージョン8からです。バージョン7以前にもフロートを解除させるために、hasLayoutをオンにしてあげます。

.sample {
	*zoom: 1;
}
.sample:after {
	content: '';
	display: block;
	clear: both;
}

5. パーセント指定することによるズレ

widthやmarginの値を割合(パーセント)で指定する場合、IE6とIE7は次のように計算します。

パーセント → ピクセルに変換 → 小数点以下四捨五入

ここで注目すべきは小数点以下を四捨五入することです。場合によっては親要素の幅より合計が大きくなってしまいます。回避策としては、%による指定をやめるか、IE6とIE7だけ少なめの数値を指定するかのいづれかになります。

.parent {
	width: 701px;
}
.child {
	float: left;
	width: 43%;
	*width: 42.5%;
}

より正確な割合を算出するためには、以下の公式によって計算する必要があります。

correct = width – ( 0.5 / container * 100 );

先ほどの例で言うと、次のようになります。

correct = 43 – ( 0.5 / 701 * 100 );

計算の結果、次のように指定することで四捨五入によるレイアウトのズレを回避することができます。

.parent {
	width: 701px;
}
.child {
	float: left;
	width: 43%;
	*width: 42.9286733238%;
}

ちなみに、IE8以降では、FirefoxやChromeと同様、小数点以下を適度に調節することで適切な表示を実現しています。OperaとSafariは小数点以下を切り捨てるので、レイアウトがズレるというほどではないですが、隙間ができてしまうことがあります(2013年4月現在)。

6. 画像の間に隙間ができる

画像を縦に並べようとしたり、要素の高さを0にしようとしたりしてもIEでは出来ないことがあります。そんなときはfont-size指定やline-height指定が邪魔をしています。特に画像は、次のように指定しておくと後が楽です。

img {
	border: none;
	font-size: 0;
	line-height: 0;
	vertical-align: top;
}

7. PNGの透過部分が灰色になる

IEはPNGのアルファチャンネルの処理がとにかく苦手なようです。PNG8や透過GIFでどうにか凌ぐこともできますが、JavaScriptのライブラリを利用すれば回避も可能です。私のオススメライブラリはDD_belatedPNGです。jQuery同様セレクタを指定するだけで処理してくれます。

jQuery(document).ready(function($){
	DD_belatedPNG.fix('img, .png-background');
});

DD_belatedPNGを特にオススメする理由は、CSSで指定した背景画像も処理してくれちゃうところです。ただ、実はちょっとおかしな挙動をしたことがあって、処理後の画像が4倍ぐらいデカくなって表示されたんです。それでじっくり調査していると、該当箇所すべてにhasLayoutスイッチャーであるzoomプロパティを指定していることに気が付きました。

.png {
	*zoom: 1;
}

ここで注目して欲しいのはzoomプロパティの値です。今回hasLayoutをオンにするプロパティとしてzoomをご紹介しましたが、この問題に気付くまではzoomプロパティの値は1を指定してました。これを100%と指定したらPNGが上手く表示されたんです(多分)。以後、hasLayoutスイッチャーとしてのzoomプロパティの値は100%を指定することにしています。間違ってたらゴメンナサイ。

8. CSS3を古いIEでも実現したい!

ドロップシャドウやグラデーションなど、CSS3には作り手が楽しくなっちゃう装飾機能が満載です。でも、IEはほぼバグが無くなったバージョン9でさえ、CSS3となるとほとんど実現できません。そこでCSS3PIEというライブラリを使います。使い方は割愛しますが、これを使えば簡単なものなら実現出来ます。

簡単なものならといったのは、出来ないこともあるってことです。例えば、色の透過を指定するrgbaなんていうのをシャドウの色として調子に乗って指定しちゃうと未対応なわけです。そんな時は-pieというプレフィクスをプロパティの前につけることで、CSS3PIE用のプロパティを別に指定することができます。

.selector {
	box-shadow: 0 1px 3px rgba( 0,0,0,0.35 );
	-pie-box-shadow: 0 1px 3px #666;
}

まとめ

実装方法って人によってクセがあるので、今回取り上げたものだけでは不十分かもしれません。IEとは付き合いが長いので、理由も覚えてないのに使わないものも多々あります。そういえばposition:fixedはIE6では無理なんでしたね。思い出したらまた追加していきますが、最後の最後でこんな内容に今更需要があるのかっていう根本的な疑問を持ってしまいました。まぁ、自分用です。そもそもこのブログ自体IEの動作確認してないし(笑)

コメント