東京都府中市、神田のWeb制作会社Maromaroのブログです

2026.11.02

# コーディング・システム開発

「z-indexを大きくしても前に出ない!」重なり順でハマったときの確認ポイント

こんにちは!
Maromaroフロントエンドエンジニアのgenです。

Webサイトを制作していると、要素の重なり順を調整したくなることがありますよね。

「ヘッダーをコンテンツより手前に表示したい」
「メニューが画像の後ろに隠れてしまう」
「ポップアップを前面に出したいのに、うまくいかない」

そんなときに使うのが、CSSのz-indexです。

「数字が大きいほうが手前に表示される」と覚えている方も多いのではないでしょうか?

ところが、いざ設定してみると、「9999にしても前に出ない…!」ということがあります。

今回は、そんなときに確認したいポイントを、サンプルと一緒にご紹介します!

まずはz-indexの基本をおさらい

z-indexは、要素が重なったときの前後関係を指定するプロパティです。

まずは、2つのボックスを重ねてみましょう。

<div class="demo">
  <div class="box box-a">ボックスA</div>
  <div class="box box-b">ボックスB</div>
</div>
.demo {
  position: relative;
  height: 200px;
}

.box {
  position: absolute;
  width: 180px;
  height: 120px;
  padding: 16px;
  box-sizing: border-box;
}

.box-a {
  top: 0;
  left: 0;
  background: #bde5ff;
  z-index: 1;
}

.box-b {
  top: 50px;
  left: 100px;
  background: #ffd3b6;
  z-index: 2;
}

この場合、重なっている部分では、z-index: 2のボックスBが手前に表示されます。

ボックスAをz-index: 3に変更すると、今度はAが手前になります。ここまではシンプルですね!

ただし、ページ内のすべての要素が、同じ場所で数字を比べているわけではありません。

これが、重なり順でハマりやすいポイントです。

確認ポイント1:z-indexが効く条件になっている?

まず確認したいのが、対象の要素のpositionです。

通常の要素に、次のようにz-indexだけを指定しても、重なり順の調整には使えません。

.box {
  z-index: 10;
}

positionの初期値はstaticです。通常の要素では、relativeやabsoluteなど、static以外の指定が必要になります。

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

元の配置を保ったまま重なり順を調整したいときは、position: relativeが使いやすいです。

ただし、FlexboxやGridのアイテムでは、position: staticのままでもz-indexが使えます。

「positionがないと絶対に効かない」と覚えるのではなく、どのようなレイアウトの中にあるかも確認しましょう。
参考:MDN「z-index」

確認ポイント2:親要素の重なり順に制限されていない?

positionも指定しているし、数字も大きくしている。それでも前に出ない場合は、親要素を含めた重なり方を見てみましょう。

ここで登場するのが「スタッキングコンテキスト」です。

名前は少し難しいのですが、まずは「重なり順をまとめて扱うグループ」と考えるとイメージしやすいと思います。

次のサンプルを見てみましょう。

<div class="stage">
  <div class="group-a">
    グループA
    <div class="label">前に出したいラベル</div>
  </div>

  <div class="group-b">グループB</div>
</div>
.stage {
  position: relative;
  height: 220px;
}

.group-a,
.group-b {
  position: absolute;
  width: 240px;
  height: 140px;
  padding: 16px;
  box-sizing: border-box;
}

.group-a {
  top: 0;
  left: 0;
  background: #bde5ff;
  z-index: 1;
}

.label {
  position: absolute;
  top: 80px;
  left: 100px;
  width: 180px;
  padding: 12px;
  background: #ffe680;
  z-index: 9999;
}

.group-b {
  top: 60px;
  left: 160px;
  background: #ffd3b6;
  z-index: 2;
}

ラベルにはz-index: 9999を指定しています。それでも、グループBと重なる部分では、ラベルが後ろに隠れてしまいます。

なぜでしょうか?

このサンプルでは、グループAとグループBが、それぞれスタッキングコンテキストを作っています。

そのため、外側では次の順番で比較されます。

グループA:z-index: 1
└ ラベル:z-index: 9999

グループB:z-index: 2

ラベルの9999は、グループAの中での重なり順です。

グループA全体がBより後ろにあるため、ラベルだけ数字を大きくしても、Bより前には出られません。
参考:MDN「スタッキングコンテキスト」

この場合はどう直す?

グループA全体を手前に出してよければ、Aの値を変更します。

.group-a {
  z-index: 3;
}

ただし、この方法ではラベルだけでなく、グループA全体が手前になります。

ラベルだけを前面に表示したい場合は、ラベルをグループの外に配置するなど、HTMLの構造を見直す方法もあります。

「どの要素を、何より前に出したいのか」を整理してから調整するのがポイントです!

確認ポイント3:transformやopacityが影響していない?

「親にはz-indexを指定していないのに…」という場合もあります。

実は、スタッキングコンテキストはz-index以外の指定でも作られます。

代表的なものが、次のような指定です。

CSSの指定 スタッキングコンテキストを作る条件
position: relative / absolute z-indexがauto以外
position: fixed / sticky z-indexの指定がなくても作られる
transform none以外
opacity 1未満
isolation isolate

これらは代表例で、ほかにも条件があります。
参考:MDN「スタッキングコンテキストを作る機能」

例えば、アニメーション用のラッパーに、次のような指定が残っているケースです。

.animation-wrapper {
  transform: translateY(0);
}

見た目には移動していませんが、transformの値はnoneではありません。この指定によって、ラッパーがスタッキングコンテキストを作ります。

フェードインで使うopacityも、0.5や0.99など、1未満の間は影響します。

「動きをつけてからメニューの重なり方がおかしくなった」というときは、対象の要素だけでなく、アニメーションを指定した親や祖先の要素もチェックしてみてください。

不要な指定なら外し、必要な指定なら、そのグループを含めて重なり順を調整しましょう。

番外編:隠れている原因がoverflowの場合も!

ここまで確認しても直らない場合、そもそも重なり順が原因ではないかもしれません。

例えば、カードの外にラベルをはみ出させるケースです。

<div class="card">
  カードの内容
  <span class="badge">NEW</span>
</div>
.card {
  position: relative;
  width: 240px;
  padding: 32px;
  background: #bde5ff;
  overflow: hidden;
}

.badge {
  position: absolute;
  top: -10px;
  right: 16px;
  padding: 4px 12px;
  background: #ffe680;
  z-index: 9999;
}

この場合、ラベルの上側がカードの外にはみ出しています。しかし、カードにoverflow: hiddenが指定されているため、はみ出した部分が切り取られます。

どれだけz-indexを大きくしても、この切り取りは解消できません。
参考:MDN「overflow」

切り取りが不要なら、overflowの指定を見直します。

.card {
  overflow: visible;
}

ただし、画像を角丸に沿って切り取りたいなど、overflow: hiddenが必要な場合もありますよね。

その場合は、画像を切り取る要素と、ラベルを配置する要素を分けると対応しやすくなります。

<div class="card">
  <div class="card-image">
    <img src="sample.jpg" alt="商品の写真">
  </div>
  <span class="badge">NEW</span>
</div>

CSSは次のようにします。ラベルの指定は先ほどと同じです。

.card {
  position: relative;
  width: 240px;
  overflow: visible;
}

.card-image {
  overflow: hidden;
  border-radius: 16px;
}

.card-image img {
  display: block;
  width: 100%;
}

.badge {
  position: absolute;
  top: -10px;
  right: 16px;
  padding: 4px 12px;
  background: #ffe680;
  z-index: 1;
}

「後ろに隠れている」のか、「はみ出した部分が切られている」のかで、対処方法が変わるということですね!

検証ツールでは、この順番で確認してみよう!

原因がわからないときは、ブラウザの検証ツールで、次の順番で調べると整理しやすいです。

1. 対象の要素を選択する

意図したCSSが当たっているか、別の指定で上書きされていないか確認します。

2. positionとz-indexを確認する

Computed(計算済み)などで、実際に適用されている値を確認します。

3. 親から祖先へたどる

z-index、transform、opacityなど、重なりのグループを作る指定がないか探します。

4. 手前に表示されている要素も調べる

相手がどのグループに属しているかを確認します。

5. overflowによる切り取りを確認する

親や祖先にoverflow: hiddenやclipがないかを見ます。

怪しい指定を見つけたら、検証ツール上で一時的に無効にしてみると、原因を絞り込みやすくなります。

ただし、無効にするとレイアウトやアニメーションに影響する場合もあります。原因がわかったら、その指定が必要な理由も確認してから修正しましょう。

数字は大きくするより、役割を決めておくと便利

重なり順を場当たり的に調整していると、

z-index: 999;
z-index: 9999;
z-index: 99999;

と、どんどん数字が増えていきがちです。

そこで、サイト内で使う値を、役割ごとに決めておくのもおすすめです。

:root {
  --z-header: 100;
  --z-menu: 200;
  --z-overlay: 300;
}

.site-header {
  position: fixed;
  z-index: var(--z-header);
}

この数字自体に決まりはありません。案件やチームのルールに合わせて設定します。

ただし、変数で管理していても、スタッキングコンテキストの影響は受けます。

値の管理と、HTML・CSSの構造の確認をセットで行うのが大切です。

まとめ

今回は、z-indexを大きくしても前に出ないときの確認ポイントをご紹介しました。

確認したいのは、次の4つです。

① 対象の要素は、z-indexが効く条件になっているか
② 親や祖先のスタッキングコンテキストに制限されていないか
③ transformやopacityが影響していないか
④ overflowではみ出した部分が切り取られていないか

「数字が足りないのかな?」と思ったときこそ、親要素までさかのぼって見てみてください。

重なりのグループがわかると、やみくもに数字を大きくしなくても、原因を整理しやすくなります。

ちょっとしたポイントですが、ヘッダーやメニューなど、日々のコーディングで役立つ場面は多いはずです。ぜひ確認してみてください!

以上、Maromaroのgenでした。

Web制作のご相談はこちら コーポレートサイト、採用サイト、LP制作まで。課題整理から公開後の運用まで、目的に合わせてご提案します。