何かと問題を起こしやすい z-index について調べる機会があったので まとめました。
要素を意図した通りの重なり順序で表示するには、根本から理解しておいた方が、結果的に早道なのではないかと思います。
この記事は W3C の勧告を元に書きましたが、z-index はブラウザによってバグ等の理由で挙動が違うこともあるようなのでご注意ください。尚、CSS3 の該当モジュールはまだ草案(Working Draft)レベルです。
前提
これはすでにご承知と思いますが、念のため。
- 要素の重なり順序は、基本的にマークアップした順に奥から手前になります。
親より子供が手前であり、兄弟ならば あとからマークアップした要素が手前に表示されます。
これを踏まえつつ、z-index を指定した場合を考えていきます。
スタック レベルとスタック コンテキスト
スタック レベルとは、要素の重なり順序を決める値です。
z-index は、要素のスタック レベルを指定するプロパティです。
スタック コンテキストとは、z-index を指定した要素をベースとする、子孫要素の集合を指します。その子孫要素たちは、「同じスタック コンテキストに所属している」と表現します。
ルート要素(html 要素)は z-index を指定しても しなくても、ルート スタック コンテキストを生成します。そのため、どの要素も初期状態ではルート スタック コンテキストに所属します。
ルール
- z-index を指定していない要素のスタック レベルはゼロです。(z-index: auto; の指定と同等)
- z-index を指定すると、スタック レベルをゼロ以外に設定できます。
同時に、z-index を指定した要素をベースとする、新しいスタック コンテキストが生成されます。
(これがクセモノです) - つまり、z-index: 0; と z-index: auto; は、スタック レベルはどちらもゼロですが、スタック コンテキストが生成されるか されないかの大きな違いがあります。
- 要素は、同じスタック コンテキスト内でスタック レベルが大きいほどマークアップ順序を無視して手前に表示されます。
- z-index は、あくまで「同じスタック コンテキスト内」の重なり順序の指定であることに注意です。
違うスタック コンテキスト内の要素に対しては重なり順序を指定できません。
ルールの詳細
上記のルールを図にしてみました。
四角はスタック コンテキスト、色は要素の親子関係を示しています。
(親) 青 > 緑 > 黄 (子孫)
div A と div D、div E と div F はそれぞれ兄弟要素です。
マークアップ順序はアルファベット順(html ~ div A ~ div F)と考えてください。
div E が破線なのは、z-index: auto; の指定ではスタック コンテキストが生成されないからです。
- div A と div D は、同じ html のルート スタック コンテキストに所属していますので、z-index が大きい div D が手前に表示されます。
- div A より div B の z-index は小さいですが、div B が手前に表示されます。なぜなら、div B は div A とは違うスタック コンテキストに所属しているからです。(div B の所属は div A のスタック コンテキスト、div A の所属は html のルート スタック コンテキストです)
所属するスタック コンテキストが違う場合には、基本的にマークアップ順序による重なり順序になります。 - div F は div E より あとにマークアップされていますが、div F が奥に表示されます。div E と div F が所属する div D のスタック コンテキストにおいて、div F の方が z-index が小さいからです。
(z-index: auto; のスタック レベルはゼロであることを思い出してください) - div C はすべての中で最も大きな z-index が指定されていますが、div D とその子孫要素より奥に表示されます。なぜなら、div C が所属しているのは div B のスタック コンテキストだからです。
- div C を最も手前に表示させたいなら、例えば div A と div B の z-index 指定を消去します。
(div A と div B の z-index 指定を消去すると、div C の所属するスタック コンテキストは html のルート スタック コンテキストになります。同じルート スタック コンテキストに所属する div D より div C の方が z-index が大きいので手前に表示されます)
さらなるルール
これで重なりの順序は自由自在?
いいえ、残念ながら あなたを更に混乱させる情報をお伝えしなければなりません。
- z-index の指定を有効にするためには、position を static 以外にする必要があります。
また、position を static 以外にすると、z-index を指定しなくても、その要素をベースとした新しいスタック コンテキストが生成されます。 - opacity を指定した要素も同様にスタック コンテキストが生成されます。
- transform を指定した要素も同様にスタック コンテキストが生成されます。
- z-index を指定しない場合、スタック レベルはどの要素もゼロです。
スタック レベルが同じとき、スタック コンテキストのベースになっている要素は、マークアップ順序を無視して、そうでない要素より手前に表示されます。
position: fixed; を指定した要素が しばしば最も手前に表示されるのはこれが理由です。
ベスト プラクティス
z-index が効かない! 重なり順序が思った通りにならない!
そんなときには、以下を試してみましょう。
- z-index を指定する要素を必要最小限にしてみる
- position の指定を消去して(static にして)位置調整は padding や margin にしてみる
- いったん opacity や transform の指定を消去してみる
- ブラウザによって重なり順序が違うようならバグを疑ってみる
参考サイト
以下のサイトも詳しく解説されています。
ちなみに、昨今CSS3なるものが流行していますが、この記事はW3CのCSS2.1勧告(と付録)を元に書いています。
と書かれていますが、調べてみたところ、CSS3 の勧告草案と CSS2.1 の勧告は、z-index の記述部分について現状、大差がないようです。
(diff した結果)
以下のサイトは、z-index も含めて すべての重なり順序の詳細が説明されています。
「コンテキスト」が「文脈」と直訳されてしまっているので少し注意です。
以下は関連する W3C の勧告と、日本語情報のページです。
- Elaborate description of Stacking Contexts(英語)
- CSS Positioned Layout Module Level 3(英語)
- Elaborate description of Stacking Contexts – CSS 2.1 spec (ja)
- CSS3の日本語訳集 – 血統の森 web実験小屋
(CSS Positioned Layout Module Level 3 の日本語版はないようです…)
最後に
筆者の英語力は並以下なので、勧告の解釈を間違えていたら ごめんなさい……
と弱気なところを見せつつ締めくくりますw 誤りはご指摘いただけると嬉しいです。
Pingback: CSSデザインについて | SHIN U DESIGN