IEの表示バグについて

IEのバグはあまりに沢山ありすぎて、多くのWebデザイナーの嫌いなものリストに「嫌いなもの:IE」と入っているほどです。

その中でも陥りがちなところをピックアップします。

その前にIE6-7の表示を確認できるツールが、Microsftから出ているので、Expression Web SuperPreviewをDLしておきます。(インストールするのにMicrosoft .NET Framework 4 (Web インストーラー)が必要)

これ以外にも、IETesterってやつがいます。こっちのほうが動作が軽くて使いやすいですが信頼性は上記のほうが上です。

参考:Windows8proへアップグレードしてみた

IE(InternetExplore)全般

IEのどれかのバージョンだけレイアウトが乱れてしまったりするときに、それを直すのをあきらめ、そのブラウザだけ処理対象からはずす、ハックという作業があります。

IE5は使っている人はそうはいないと思いますが、IE6はXPの標準搭載ブラウザでまだちらほらいるので、IE6以外と場合ってのも最悪の時は使うかもしれません。

<!-- HTML内 -->
<!--[if IE 8]>
IE8の場合の記述
<![endif]-->
 
<!--[if lt IE 9]>
IE9未満(IE5,6,8)の場合の記述
<![endif]-->
 
<!--[if gte IE 9]>
IE9以上(IE9,10)の場合の記述
<![endif]-->
 
<!--[if !IE 6]><!-->
 IE6以外(IE5,7,8etc)のブラウザへの記述
<!--<![endif]-->
 
<!--[if !IE]><!-->
 IE以外のブラウザへの記述
<!--<![endif]-->
/* CSS内 */
/* IE6は!importantを無視し、他のブラウザはimportantを最優先する(インポータントハック) */
#a1 {
	height:100% !important;
	height:50%;
	}

/* IE6以下(スターハック) */
* html #a1 {
	height:100%;
	}

/* IE6以外(チャイルドセレクタハック) */
html > body #a1 {
	height:100%;
	}

/* IE6以外(隣接セレクタハック) */
html + body #a1 {
	height:100%;
	}

/* IE6以下(アンダースコアハック) */
#a1 {
	_height:100%;
	}

/* IE7(スタープラスハック) */
*+ html #a1 {
	height:100%;
	}
*:first-child + html #a1 {
	height:100%;
	}

!importantハックは上にimportantで下にIE6用の命令を書く。チャイルドセレクタハックや隣接セレクタハックは、IE6がチャイルドセレクタ等に対応していないことを利用したハックで、html > body文等を書けばハックになる。

その他の細かいハック方法はこちら(ハックリスト)等を参照。

加えて、各要素ごとでなく、各セレクタごとにハックも可能。

/* CSS内 */
/* IE6は!importantを無視し、他のブラウザはimportantを最優先する(インポータントハック) */
#a1 {
	_zoom:1; /*IE6のみ適用*/
	*height:50%; /*IE6と7のみ適用*/
	}

zoomはIE7独自プロパティで、hasLayoutの値をfalseからtrueに変えるという。これによってIE6非対応のプロパティがなんとか挙動を保つらしい。(参考)

IE6

続いてIE6のバグです。

フッター固定時に遭遇する(min-height未対応)

コンテンツが少ないときでもフッターを画面下に固定するテクニックがありますが、IE6ではmin-heightに未対応ですので、プラスアルファでスターハックを使ってプロパティを指定しなければなりません。

フッター固定では、以下のような骨格があったとして

<!-- HTML内 -->
<body>
<div id="a1234">
    <header id="a1">ヘッダー</header>
    <div id="a23">
        <section id="a2">コンテンツ</section>
        <aside id="a3">サイドバー</aside>
    </div>
    <footer id="a4">フッター</footer>
</div>
</body>
/* CSS内 */
html {
	height:100%;
	}
#a1234 {
	min-height:100%;
	postion:relative;
	height:auto !important; /* IE6 */
	height:100%; /* IE6 */
	}
#a23 {
	padding-bottom:160px;
	}
#a4 {
	position:absolute;
	bottom:0;
	height:160px;
	}

まず、htmlとbodyがコンテンツによらず広がるようにheight:100%を指定、ヘッダーからフッターまでを包括しているdiv#a1234に対してmin-height:100%を指定して、コンテンツが少ない場合のheightはブラウザの高さでコンテンツがブラウザの高さよりも飛び出るくらい多くなったらその高さにする。

つまり、min-heightは高さの最小値で、設定した最小値を超えるコンテンツの量であれば、heightはmin-heightで指定した数値を超えて広がります。

#a1234をposition:relativeを指定して絶対は位置の際の基点とし、footerをbottom:0で絶対配置する。

footerの高さを適当の高さにしたら、コンテンツとサイドバーを包括するdiv#a23に対してpaddingでfooterと同じ高さ分の余白をとる。

IE6以外であればここで終わりなわけですが、IE6はmin-heightに対応していないのと、heightを指定しなくてもそのボックスの中身に応じてheightが自動で広がってしまうバグがあるために、中身があまりないときはheight:100%を、中身が多いときはautoで広がるようにする(インポータントハック)を使用してmin-heightと同じような命令になるようにしています。この2行がIE6のための記述となります。

ボタン固定時に遭遇(position:fixed未対応)

IE6はposition:fixedに対応していないので、指定した要素はそのまま下の行に追加される形で配置されてしまいます。

lightboxウィンドウ作成で必ず使用するプロパティですが、大体はプラグインを利用することになると思うのでその辺は大丈夫でしょう。とすると、次の利用機会はツイッターのfollow meボタンのようなスクロールイベントに合わせて一定位置に表示されるボタンの作成の時ではないでしょうか。

設置座標が画面上から数えることができる位置であれば、

/* CSS内 */
* html #z1 {
	position:absolute;
	top:0;
	} 

スターハックでIE6だけpositionをabsoluteに、他のブラウザはposition:fixedで配置し、IE6には絶対配置のTOP座標をスクロールイベントに応じて切り替えるIE独自のexpression命令を指定します。(absoluteはfixedの後に記述します前後逆はだめです)

/* jQuey内 */
$(function(){
	if($.browser.msie && $.browser.version<7){
		$(window).scroll(function(){
			$("#z1").get(0).style.setExpression("top","$(document).scrollTop()+'px'");
		});
	};
}); 

トップからの座標は問題ないのですが、ボトムからの座標はブラウザの高さ幅に大きく左右されてしまうので非常に難しいです。その上scrollBottomのような命令もありません。

height()メソッドを使用するとwindowやdocumentの高さを返してくれます。windowはブラウザの縦横幅、documentはページの縦横幅(ページが縦に長ければブラウザの高さを突き抜けた幅)です。

これを使用して、

/* jQuey内 */
$(function(){
	if($.browser.msie && $.browser.version<7){
		$(window).scroll(function(){
			$("#z1").get(0).style.setExpression("bottom","($(document).scrollTop()+$(window).height())+'px'");
		});
	};
}); 

とすればいいかなと思ったが、なぜかbottomの座標を切り替えることができないようなので、

<!-- HTML内 -->
<div id="z1">
<a href="#" id="z2">
ページトップへ
</a>
</div>
/* CSS内 */
#z1 {
	position:fixed;
	bottom:20px;
	right:20px;
	background:#999;width:100px;height:50px;
	}
* html #z1 {
	position:absolute;
	}
/* jQuey内 */
$(function(){
	if($.browser.msie && $.browser.version<7){
		$(window).scroll(function(){
		$("#z1").get(0).style.setExpression("top","($(document).scrollTop()+$(window).height()-70)+'px'");
		});
	};
}); 

のようにスクロールトップの座標にウィンドウの高さを加えて、そこからボタンの高さ幅(50px)+bottomの幅(20px)を引いた座標をTOPとして配置します。

overflowがなんちゃらとか書いてあったサイトもありましたが、html5だとDOCU宣言がないから?スクロールバーが動かなくなってしまって断念。プラグインもあります要検索。

透過PNG使用時・グラデーション使用時に遭遇(opacity未対応)

IE7以下はopacityプロパティに対応していないため、同じような環境を作るためにはIE独自拡張のfilterプロパティ(alpha)を使用する必要があります。

/* CSS内 */
#z1 {
	opacity:0.4; /*IE8以上他*/
	filter:alpha(opacity=40); /*IE7以下*/
	}

backgroundのグラデーション(CSS3プロパティ)にも未対応なのでfilterプロパティ(gradient)を使用して実装します。

/* CSS内 */
#z1 {
	background: linear-gradient(to bottom,  #4c4c4c 0%,#595959 12%,#666666 25%,#474747 39%,#2c2c2c 50%,#000000 51%,#111111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%); 
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#4c4c4c', endColorstr='#131313',GradientType=0 );
	}

ただし、原因はよくわかりませんが、IE6にグラデーションとしてfilterを指定したときに、全てではないのですが黒画面になってしまうことがあります。

透過PNGはIE6で未対応なので、IE6のみにfilterプロパティ(AlphaImageLoader)を使用して実装します。

/* CSS内 */
#z1 {
	filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="a.png",sizingMethod="scale");
	}

srcは読み込まれたHTMLからの相対パスか絶対パス、sizingMethodは、scale(画像→要素サイズに合わせて表示)、image(要素→画像のサイズに合わせて拡張)、crop(画像サイズ変化なし)を指定できる。

IE6ではimgタグで配置されているPNG画像をそのまま透過処理できない(背景画像として指定して、background:noneにしているのは大丈夫)ので、一旦なんらかのダミー画像にjavascriptで変更した後に、そのダミー画像をfilter適用後のPNG画像に変更するという手間が必要です。

とはいえ、こんなめんどくさいことをせずしてiepngfix.htcというプラグインがありますので、DL後、特定のフォルダに入れて、HTMLからの相対パスを入れて適用させれば簡単に実装できます。

/* CSS内 */
* html ul#z1 img {
	behavior:url(png/iepngfix.htc);
	}

フロート時にマージンが広がる問題

floatプロパティを指定した要素に対して左右のmarginを指定すると、なぜかIE6だけのmarginが2倍になってしまうという超有名なIE6のバグ。

対処法はmarginを基本的に使用せず、paddingで指定するか。もしくは、floatされる要素に対してdisplayにinlineをしていするか。のどちらかです。

floatされる要素のdisplay値は無視されてfloatされるので、通常はdisplay:inline指定のほうを使用します。

リスト縦並びのときの問題

リストのliの中の文字や画像にa要素を指定することはよくあることで、文字だった場合、リストタグはinline要素なのでマウス範囲が広がらないIE6のバグ対策用にaタグに対してdisplay:blockを指定しますが、このとき縦ならびになっているとIE6でリストの間に空白ができてしまう。

これを防止するため、liタグにline-height:0を、aタグにline-height:normalを指定する。

その他の問題

  • border-radiusを指定した要素にmarginを指定したら文字がずれて表示された。→スターハックでnoneへ
  • box-shadowを指定した要素の背景がshadowの色に塗りつぶされた。→スターハックでnoneへ
  • タイトルタグをメタタグの前に書くと強制的にSJISに変換されるため文字がバグったり白い画面になったりする。→タイトルの全角文字がメタタグの前にあるとなんでかPHPとかで画面をポップさせたりするときにUTF-8で指定していたとしてもSJISに強制的に変換されてしまうという致命的なバグ(IE11ですらなおっていない)
  • GoogleAdsenseとsyntaxhighlighterの同時実行でアドセンスの外部スクリプト読み込みエラーが起こりsyntaxheighlighterが上手く適用されない(アップすれば直る)
  • IE7以下?はGoogle+1ボタンが正常に表示されないことがある。
  • ulやolにwidthを指定するとリストマークが消えてしまうので、divでくくって指定しなければならない。

IE8以下

IE8以下はHTML5に対応していませんので外部プラグインを読み込んでタグを使えるようにしなければなりません。

CSS3は主にIE9以下が未対応と考えていいので、考慮するために外部ファイルを用いたり、グラデーションにはfilterプロパティを使用します。

IE以外でも

画像下の謎の空白

画像を何気なく配置したとき、画像下に謎の空白が生じることがあります。

divやp等のブロックレベル要素の中にimgタグを格納するときに出てくるもので、divとかにmargin:0を設定しても治りません。

これを治すには、imgに対して、vertical-align:bottom;を設定する必要があります。よく遭遇するものですので覚えておくとよいかと思います。

ブラウザ全般の相性問題

lightboxとsyntaxheighlighterの問題

syntaxheighlighterの項を参照。

ライブラリ同士のコンフリクト

lightbox系統とzenbackを導入したりしたときに生じやすい不具合で、$関数の定義が各ライブラリやバージョンにより異なるのが原因。

IEでzenbackとjQueryのコンフリクトによる不具合を回避する方法でその対処法が解説されています。

一般的なのは、

//js内
<script>
var $j = jQuery.noConflict();
$(function() {
    $('#gallery a').lightBox();
});
</script>

のように、jQueryが定義するwindow.$関数をjQuery.noConflict()メソッドを使用することで削除します。一箇所でもこの命令を使うとjQueryの略語として定義されていた$は使うことができなくなります。(上の例では$jと毎回記述する必要がある)

noConflict()関数の引数をtrueにすると、window.$とwindow.jQueryの両方が削除されてしまうため、プラグインを追加できない等不具合が起きることがあるので引数の指定は避けてください。

コメントor補足情報orご指摘あればをお願いします。

(件名or本文内でキーワード検索できます)



  • << 前のページ
  • 次のページ >>
ページトップへ