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でした。










