z-indexが効かない時の見落としやすい原因|現場で使える実践テクニック

C
クリオ
Web制作ディレクター / フロントエンジニア

こんにちは!

今日は「z-indexが効かない時の見落としやすい原因」について解説します。
これ、ほんま現場でめっちゃよく出会うトラブルなんですよ。

z-indexが効かないのはなぜ?よくある勘違い

僕も最初のころ、モーダルウィンドウやドロップダウンメニューを作ってるときにz-index: 9999を指定しても、なぜか背後の要素に隠れちゃうっていう経験をしました。
その時は本当に困って、デベロッパーツールで何度も確認して…ほんま無駄な時間を過ごしましたね。

実はz-indexには、多くの人が知らない落とし穴があるんです。
それは「z-indexは、同じスタッキングコンテキスト内でしか比較されない」という概念です。

よくある勘違いはこちら:

  • z-indexの値が大きければ、どんなときでも前に来ると思っている
  • 親要素にpositionが設定されていないのに、子要素のz-indexが効くと思っている
  • positionstaticのままz-indexを指定すると効くと思っている
  • 兄弟要素同士で、単純に大きい数値が勝つと思い込んでいる

特に3番目のやつ、僕も後輩指導してるときに「あ、これですね」って気づくことが多いです。

スタッキングコンテキストを理解する

「スタッキングコンテキスト」という言葉、聞いたことありますか?
これを理解できると、z-indexのトラブルの9割は解決します。

スタッキングコンテキストっていうのは、簡単に言うと「レイヤーの積み重ねの境界」みたいなものなんです。
新しいスタッキングコンテキストが作られると、そこから「独立した世界」が生まれるイメージですね。

スタッキングコンテキストが作られる主な条件:

  • position: relative/absolute/fixedz-indexauto以外の値が指定されている
  • opacity1より小さい
  • transformnone以外
  • filternone以外
  • will-changeが上記のプロパティを指定している
  • flexコンテナの子要素でz-indexが指定されている
  • gridコンテナの子要素でz-indexが指定されている

ここが重要なんですけど、例えば親要素にopacity: 0.9が指定されてたら、その子要素のz-index: 9999は、親の外にははみ出せないってわけです。

実際の例を出しますね。
最近プロジェクトで出会ったのが、背景を少し暗くするために親にopacityを設定してた案件。
その中のドロップダウンメニューが絶対に上に来ないって、デザイナーさんから指摘されました。
原因は、opacityがスタッキングコンテキストを作ってたってわけですね。

実際のデバッグ手順と対処法

では、実際にz-indexが効かないときは、どう対処するか見ていきましょう。

ステップ1:positionとz-indexを確認

まず第一に、z-indexを指定したい要素にpositionがちゃんと設定されてるか確認してください。
position: static(デフォルト)では、z-indexは完全に無視されます。

デベロッパーツールの「Elements」タブで、該当要素を選択して、Stylesパネルを見てみるといいですよ。

ステップ2:親要素のプロパティをチェック

親要素と祖先要素をさかのぼって、以下をチェック:

  • opacityが1より小さくないか
  • transformが指定されていないか
  • filterが指定されていないか
  • position: relativez-indexが指定されていないか

特にopacityは見落としやすいんですよ。
背景色を半透明にするためにrgbaを使うのとは違って、opacityプロパティを使うとスタッキングコンテキストが作られちゃいます。

ステップ3:兄弟要素の関係を確認

z-indexは、同じ親を持つ兄弟要素間でしか比較されません。
つまり、別の親を持つ要素同士では、数値の大きさだけでは決まらないってことです。

例えば、こんな構造があったとします:

  • 親A(子:モーダル)
  • 親B(子:背景オーバーレイ)

この場合、親A自体が親Bより奥にあれば、モーダルが持つz-index: 9999も役に立たないわけです。

ステップ4:修正の方法

よくある修正パターンをお伝えします:

  1. 問題の要素にposition: relativeを追加(もしくはabsolutefixedに変更)
  2. 親要素からopacityを別の方法に変更(rgba背景色やpseudo要素を検討)
  3. スタッキングコンテキストを意図的に作り直す(親にposition: relativez-index: 1を追加)
  4. 必要に応じてHTMLの構造を見直す(モーダルやオーバーレイを親の外に移動)

現場では、特に4番目の「HTML構造を見直す」ってのが重要なんですよね。
CSSだけで無理に解決しようとすると、後々メンテナンスが大変になっちゃいます。

まとめ

z-indexが効かないって思ったときは、ほぼ100%スタッキングコンテキストの問題です。
「なぜ効かないんだろう」って思ったら、まずは親要素と祖先要素を見る。
これが習慣になると、こういうトラブルは一瞬で解決しますよ。

デベロッパーツールで丁寧に調べて、どのプロパティがスタッキングコンテキストを作ってるのか特定する。
これができるようになると、CSS周りのトラブルって本当に怖くなくなります。