ヘッダーを前面に表示したいのに、画像やアニメーションの後ろへ隠れてしまう。
モーダルのz-indexを大きな数値に変更したのに、別の要素より前に出てこない。
Web制作では、このような重なり順の問題がよく発生します。
解決しようとしてz-indexを9999、99999と増やしても、原因によっては表示が変わりません。z-indexは、Webページにあるすべての要素を一つの順位表に並べる仕組みではないからです。
今回は、z-indexが効かない主な理由と、重なり順の問題を整理して解決する方法を解説します。
z-indexは要素の重なり順を決める
Webページ上の要素が重なったとき、どちらを前に表示するかを指定するために使われるのがz-indexです。
数値が大きい要素ほど前、小さい要素ほど後ろに表示されるのが基本です。
たとえば、通常のコンテンツより固定ヘッダーを前に表示したり、ページ全体よりモーダルを前に表示したりするときに使います。
ただし、数値の大小だけで必ず順番が決まるわけではありません。
z-indexを理解するには、要素が所属している「重なりのグループ」も考える必要があります。
z-indexを設定しただけでは効かない場合がある
z-indexは、どのような要素に設定しても必ず有効になるわけではありません。
要素の配置方法やレイアウトの状態によって、重なり順を変更できる条件が異なります。
z-indexが効かないときは、まず対象要素のpositionがどのように設定されているかを確認します。
一般的には、relative、absolute、fixed、stickyなどが設定された要素でz-indexが使われます。
また、FlexboxやGridの子要素では、positionが設定されていなくてもz-indexが機能する場合があります。
「z-indexを書いたから前に出る」と考えるのではなく、その要素が重なり順を変更できる状態なのかを確認することが大切です。
親要素が違うと単純に数値を比較できない
z-indexが効かない原因として特に多いのが、比較している要素の親が異なるケースです。
たとえば、ヘッダーに大きなz-indexを設定していても、そのヘッダーを囲む親要素自体が別のグループより後ろに置かれていると、ヘッダーだけを前へ出せないことがあります。
子要素は、基本的に親要素が所属する重なりの範囲から自由に抜け出せません。
これは、引き出しの中にある書類をイメージすると分かりやすくなります。
書類の順番を入れ替えても、引き出し自体が別の棚の後ろにあれば、棚より前には出てきません。
子要素のz-indexだけでなく、親要素同士の重なり順を確認する必要があります。
スタッキングコンテキストとは
要素の重なり順を管理するグループを、スタッキングコンテキストと呼びます。
それぞれのスタッキングコンテキストの中では、z-indexによって子要素の順番を決められます。
しかし、別のスタッキングコンテキストに所属する要素とは、子要素の数値だけでは直接比較できません。
親の重なり順が先に決まり、その親の中で子要素の順番が決まります。
そのため、片方の子要素に非常に大きなz-indexを設定しても、親要素のグループが後ろにあれば前面へ表示されません。
z-indexの問題は、数値ではなくスタッキングコンテキストの関係が原因になっていることが多くあります。
position以外でもグループが作られる
スタッキングコンテキストは、positionとz-indexの組み合わせだけで作られるものではありません。
次のような指定がある要素でも、新しい重なりのグループが作られる場合があります。
transformによる変形
opacityによる透明度
filterによる画像効果
isolationによる分離
一部のアニメーション設定
FlexboxやGrid内のz-index
要素を最適化するための特定の指定
特にtransformは、要素の移動や拡大、アニメーションで頻繁に使われます。
見た目の位置を調整するためにtransformを設定しただけでも、重なり順へ影響することがあります。
原因が見つからないときは、対象要素だけでなく、親要素にこれらの指定がないか確認します。
数値を9999にしても解決しない理由
z-indexを9999にする方法は、一時的に問題が解決したように見えることがあります。
しかし、別のスタッキングコンテキストに閉じ込められている場合は、数値をどれだけ大きくしても意味がありません。
また、大きな数値を次々と追加すると、サイト全体の重なり順を把握できなくなります。
ヘッダーを999、メニューを9999、モーダルを99999というように増やしていくと、新しい部品を追加するたびにさらに大きな数値が必要になります。
重要なのは最大の数値を探すことではなく、どの要素同士が同じグループ内で比較されているかを確認することです。
overflowによる切り取りは別の問題
要素が前に出ないように見えても、実際には親要素の範囲で切り取られている場合があります。
親要素に、はみ出した部分を隠す指定があると、子要素へ大きなz-indexを設定しても、親の外側へ表示できません。
よくあるのが、スライダーや装飾を作るために親要素へoverflowの設定を行い、その中にあるメニューや吹き出しまで切れてしまうケースです。
これは重なり順の問題ではなく、表示範囲の問題です。
z-indexを変更する前に、「後ろへ隠れているのか」「親の範囲で切れているのか」を見分ける必要があります。
fixedを設定しても必ず画面基準になるとは限らない
固定ヘッダーやモーダルでは、positionのfixedが使われます。
通常は画面を基準に配置されますが、祖先要素にtransformなどが設定されていると、その祖先要素を基準にしたような動作になる場合があります。
その結果、スクロール時の位置や重なり方が想定と変わることがあります。
モーダルや画面全体を覆う背景は、深く入れ子になった部品の中ではなく、ページ全体に近い階層へ配置すると管理しやすくなります。
JavaScriptで表示を切り替える場合も、どの要素の中へ追加されているのかを確認することが重要です。
重なり順は役割ごとに決める
サイト全体でz-indexの基準を決めておくと、後から機能を追加しても整理しやすくなります。
たとえば、次のように役割を分けて考えます。
通常のコンテンツ
装飾や背景
固定ヘッダー
開閉メニュー
画面を覆う背景
モーダル
緊急メッセージ
数値を連続させる必要はありません。
役割ごとに一定の間隔を空けておけば、途中へ新しい要素を追加しやすくなります。
ただし、ルールを作っても、不要なスタッキングコンテキストが多ければ管理は複雑になります。重なり順を作る指定そのものを必要最小限にすることも大切です。
原因を調べるときの順番
z-indexが思ったように効かない場合は、次の順番で確認すると原因を切り分けやすくなります。
対象要素にz-indexが適用される状態か
重なっている相手はどの要素か
両方の親要素は同じか
親要素にz-indexが設定されていないか
祖先要素にtransformやopacityなどがないか
overflowで切り取られていないか
HTML上の配置場所を変更した方が自然ではないか
ブラウザの開発者ツールを使い、怪しい指定を一つずつ無効にしながら確認すると原因を見つけやすくなります。
複数の指定を同時に変更すると、何が影響していたのか分からなくなるため注意が必要です。
まとめ
z-indexは、要素が重なったときの表示順を調整するためのものです。
ただし、Webページ上のすべての要素を数値だけで並べているわけではありません。
要素はスタッキングコンテキストというグループに分かれており、親要素の重なり順によって、子要素が前へ出られる範囲も決まります。
そのため、z-indexを大きくしても解決しないときは、親要素、transform、opacity、overflowなどを確認する必要があります。
数値を増やし続けるのではなく、どの要素がどのグループに所属しているのかを調べる。
この考え方を身につけることで、固定ヘッダー、メニュー、モーダル、装飾などの重なりを整理しやすくなります。