本文へスキップ
HTML / CSS 基礎 CSS z-index トラブルシューティング

z-index が効かないときに確認すること

更新日:2026-08-02

HTML / CSS を勉強していると、かなりの頻度で遭遇するのが、

z-index が効かない…

問題です。

例えば、

  • モーダルが前に来ない
  • メニューが画像の後ろに隠れる
  • ヘッダーが重なり負けする
  • position: fixed が埋もれる

などです。

初心者の頃は、

z-index: 999999;

みたいな数字を増やし始めます。

しかし実際には、

数字だけの問題ではない

ケースがかなり多いです。

今回は、

z-index が効かないときに確認すること

を整理していきます。


今回使用するファイル構成

この回では、次のファイルを使用します。

html-practice/
├── index.html
└── css/
    └── style.css

まず z-index とは?

z-index は、

前後の重なり順

を決めるCSSです。

数字が大きいほど前に表示されます。


<div class="red"></div>
<div class="blue"></div>
.red {
  position: absolute;
  z-index: 1;

  width: 200px;
  height: 200px;
  background: red;
}

.blue {
  position: absolute;
  top: 50px;
  left: 50px;

  z-index: 2;

  width: 200px;
  height: 200px;
  background: blue;
}

この場合、

blue のほうが前

になります。


しかし z-index は罠が多い

初心者がハマりやすい理由は、

z-index だけでは動かない

からです。


1. position が必要

かなり重要です。


NG例

.box {
  z-index: 999;
}

これだけでは効かないことがあります。


OK例

.box {
  position: relative;
  z-index: 999;
}

なぜ?

z-index は基本的に、

position が設定された要素

で動作します。

よく使われるのは、

position: relative;
position: absolute;
position: fixed;

です。


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

ここが z-index 最大の難所です。

ただし初心者のうちは、

重なり専用のグループ

と思うとかなり理解しやすいです。


例えばこういうHTML

<div class="group-a">
  <div class="red"></div>
</div>

<div class="group-b">
  <div class="blue"></div>
</div>

CSS

.group-a {
  position: relative;
  z-index: 1;
}

.group-b {
  position: relative;
  z-index: 2;
}

.red {
  position: relative;
  z-index: 9999;
}

.blue {
  position: relative;
  z-index: 1;
}

どっちが前?

初心者は普通、

9999 の red が前!

と思います。

しかし実際には、

blue が前

になります。


なぜ?

理由は、

  • red は group-a の中
  • blue は group-b の中

だからです。

つまり、

  • 子同士ではなく
  • 親グループ同士で勝負している

のです。


イメージするとこう

  • group-a (z-index:1)
  • └ red (z-index:9999)
  • group-b (z-index:2)
  • └ blue (z-index:1)

この場合、

まず比較されるのは、

group-a vs group-b

です。

結果、

group-b のほうが前

になります。

だから、

group-b の子供達

が全部前へ出ます。


超重要ポイント

子要素は、

親グループの外では戦えない

です。

これが z-index 最大の罠です。


3. transform が原因

かなりよくあります。


.parent {
  transform: translateX(0);
}

これだけで、

新しい重なりグループ

が作られます。

つまり、

突然「別世界」

になるのです。


よくある事故

モーダル

モーダル z-index:999999

なのに前に出ない。


原因

親にこれがある。

transform: translateY(0);

つまり

モーダルが、

transform親の世界

へ閉じ込められているのです。

だから、

外側のヘッダー

に負けたりします。


4. overflow: hidden

これもかなり多いです。


.parent {
  overflow: hidden;
}

すると、

はみ出した部分

が切られます。


よくあるケース

  • ドロップダウンメニュー
  • ツールチップ
  • モーダル

など。


5. fixed が効かない問題

これも初心者がハマります。


原因

親に transform があると、

position: fixed;

の基準がおかしくなることがあります。


よくある症状

fixed のはずなのに画面固定されない

です。


6. 数字を増やしても解決しない

重要です。


よくある状態

z-index: 999999999;

それでも負ける。


なぜ?

z-index は、

別グループ同士

だと比較されないからです。


学校のクラスで例えると

かなりイメージしやすいです


A組

田中(9999点)


B組

佐藤(1点)


でも学校ルール

B組のほうが優先

なら、

田中9999点でも負ける

みたいな感じです。


つまり z-index は

世界が同じなら比較できる

です。


スタッキングコンテキストを作るもの

よく遭遇するのはこれです。

position + z-index
transform
opacity
filter

特に、

transform

が本当に多いです。


Chrome DevTools を使おう

実務ではかなり重要です。


確認ポイント

F12 を押して、

Elements

を開きます。


見る場所

  • position
  • z-index
  • overflow
  • transform

を確認します。


実務で多い原因ランキング

かなりリアルです

原因 多さ
position忘れ 超多い
transform 超多い
overflow:hidden 多い
親z-index 多い
opacity/filter 中くらい

実際の現場では?

現場では、

z-index を適当に増やす

のは危険視されます。

なぜなら、

あとで管理不能になる

からです。


よくある運用

例えば、

用途 z-index
通常要素 1
ヘッダー 100
メニュー 500
モーダル 1000
ローディング 9999

みたいに、

ルール化

することがあります。


困ったら確認する順番

かなり重要です


① position がある?

position: relative;

など。


② 親に transform ない?

かなり多い。


③ overflow:hidden ない?

切られてない?


④ 別グループになってない?

スタッキングコンテキスト問題。


⑤ DevTools で確認

最終兵器です。


まとめ

z-index が効かない原因は、

数字不足

ではないケースが多いです。

本当に重要なのは、

重なりのルール

を理解することです。

特に、

  • position
  • transform
  • overflow

は超重要です。

最初はかなり混乱しますが、

「あ、また transform か」

となっていきます