CSS の z-index について整理してみる

今日は CSS Nite in Ginza, Vol.31に行ってきます。テーマは「CSSレイアウト:IE 6対応のかんどころ/小林 信次(まぼろし)」ということで、以前「CSS Nite ビギナーズに参加した感想とか要望とか」で書いた「CSS Nite への要望っぽいこと」が実現した感じで、すごく楽しみです。

僕は Web制作の現場にいないので、実務経験が少ないです。ですので、日頃、Web 制作を仕事としてやっている人が、サッと解決できちゃうようなことにもハマったりします。

そういった点を補うには、今日の CSS nite のようなテーマはすごくありがたいです。

さて、前置きが長くなりましたが、今日は以前ひっかかった IE6 の z-index の解釈について、改めて整理してみました。

どんなシーンでハマったか

このブログもそうですが、最近ページ上部にグローバルナビゲーションを配置し、それを jQuerysuperfish などを使って、スルスルっと表示させるレイアウトをやることが多いです。

このとき、スルスルっとさせたときのメニューが、IE6 だと隠れちゃったりするのです。

z-index について

ます、最初に CSS の z-index について「z-index CSS 表示と配置 | World Wide Web Guide」を参考に復習しておきましょう。

z-indexプロパティの指定がない場合、及び z-indexプロパティに "auto" が指定されている場合の位置要素されている要素の重なり方は、文書のソース内であとに記述されている要素ほど上に重ねられて前面に表示されることになります。また、位置要素されている要素と、位置指定されていない要素(position : static ; が指定された要素、及び positionプロパティの指定されていない要素)とでは、位置指定された要素が上に重なって前面に表示されることになります。そこで、z-indexプロパティは重ね合わせの順番が上手くいかないときに、ソース内で要素が記述されている位置に関係なく、要素の重ね合わせる順序を調整することができます。

サンプルのソース

上記の z-index の性質を踏まえて、以下のようなソースで実験してみます。CSS も HTML 内に書いちゃっています。

実用的なイメージとしては、div#header の中に z-index を適用するグローバルナビゲーション(ここでは div#floating)がある場面を想定しています。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">
<head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
 <title>IE6 のバグかな?</title>
 <style type="text/css">
 /* 基本レイアウト */
 * { margin: 0; padding: 0;}
 #header { width: 400px; height: 200px; background: #0000DA; color: #ffffff;}
 #floating { width: 200px; height: 200px; background: #ECEC00; color: #000000; top: 100px; left: 100px;}
 #contents { width: 400px; height: 200px; background: #46A56A; color: #ffffff;}
 #primary { width: 200px; height: 150px; background: #cccccc; color: #000000; float: left;}
 #secondary{ width: 200px; height: 150px; background: #333333; color: #ffffff; float: left;}

 /* 以下の設定が影響 */
 #header { position: relative;}
 #floating { position: absolute; z-index: 10;}
 #contents { }
 </style>
</head>
<body>
<div id="page">
 <div id="header">
 header div. header div. header div. header div. header div. header div. header div. header div. header div. header div. 
 <div id="floating">floating box. floating box. floating box. floating box. floating box. floating box. </div>
 </div>
 <div id="contents">
 <div id="primary">primary div. primary div. primary div. primary div. primary div. primary div. primary div. primary div. primary div. primary div. </div>
 <div id="secondary">secondary div. secondary div. secondary div. secondary div. secondary div. secondary div. secondary div. secondary div. secondary div. secondary div. </div>
 </div>
</div>
</body>
</html>

これを IE6 で表示すると次のようになります。Firefox でも同様です。

z_ind_ie6_01.jpg

先ほどの z-index の説明からも、position: static; 以外で位置指定されている要素(#header、#floating)と、位置指定されていない要素(#contents)とでは、位置指定された要素が上に重なって前面に表示されているので正しい表示です。

ソース内で後に記述された要素に position 設定を加えるとおかしくなる

ここで、上記の CSS の位置に関わる部分を次のように変更してみます。

 /* 以下の設定が影響 */
 #header { position: relative;}
 #floating { position: absolute; z-index: 10;}
 #contents { position: relative;}

すると、Firefox では表示は変わりませんが、IE6 では z-index: 10; が設定されている div#floating が div#contents と重なっている部分が隠れてしまいます。

z_ind_ie6_02.jpg

本来 position: static; 以外の要素は、後から記述された要素が前面になるところを、「z-index によって記述の順序に関係なく、要素の重なりを調整することができる」はずなので、これはおかしいです。

もし、#floating に z-index: 10; が設定されていなければ、Firefox でも上の画像のようになります。

対処方法

IE6 でこの状態を回避するには、次のように #header に z-index: 1; を加えればOKです。

 #header { position: relative; z-index: 1;}
 #floating { position: absolute; z-index: 10;}
 #contents { position: relative;}

z_ind_ie6_01.jpg

つまり、IE6 の場合、position: static; 以外の要素が入れ子になっている場合、子要素に z-index を指定しても正常に反映されず、「親要素の重なりの順序が優先」されるようです。

試しに、CSS を次のように変更してみるとどうでしょうか。

 #header { position: relative; z-index: 1;}
 #floating { position: absolute; z-index: 10;}
 #contents { position: relative; z-index: 1;}

この場合、Firefox でも IE6 でも次のような表示になります。

z_ind_ie6_02.jpg

つまり、Firefox でも IE6 でも、いくら子要素の z-index の値を大きくしても、隣接する親要素の両方に z-index が設定されていると、その親要素同士の重なり順序が優先されるようです。

続いて、次のように後に記述された親要素のみに z-index が指定されているとどうなるでしょうか。

 #header { position: relative;}
 #floating { position: absolute; z-index: 10;}
 #contents { position: relative; z-index: 1;}

この場合、Firefox では z-index の値が優先され、IE6 では親要素同士の重なり順序が優先されるようです。

[ Firefox の場合]

z_ind_ie6_01.jpg

[ IE6 の場合]

z_ind_ie6_02.jpg

まとめ

これらをまとめると、CSS の z-index プロパティは、ブラウザによって次のように扱われるようです。

[ Firefox の場合]

  • 仕様で定められている通り。
  • 隣接する親要素の両方に z-index が設定されている場合は、子要素の z-index よりも隣接する親要素の重なり順序が優先する。
  • それ以外の場合は、z-index の値が優先する。

細かくはチェックしていませんが、おおむね他のモダンブラウザも同様でした。

[ IE6 の場合]

  • 隣接する親要素の重なり順序が優先する。

以上です。