CSS

z-indexが効かない原因と直し方|重なり順・position・stacking context

CSSのz-indexが効かない原因と直し方を20項目で解説します。position、親要素、stacking context、transform、opacity、overflowの影響など、重なり順のトラブルを整理します。

この記事の目次
  1. 1. positionが指定されていない
  2. 2. z-indexがautoのままになっている
  3. 3. 親要素のz-indexが低い
  4. 4. 比べたい要素が別の親に入っている
  5. 5. 親にtransformが指定されている
  6. 6. 親にopacityが指定されている
  7. 7. filterやbackdrop-filterが指定されている
  8. 8. isolation: isolate が指定されている
  9. 9. mix-blend-modeが指定されている
  10. 10. fixed要素がtransformの親に閉じ込められている
  11. 11. 同じz-indexなら後にある要素が前に出る
  12. 12. マイナスのz-indexで後ろに隠れている
  13. 13. overflowで切り取られている
  14. 14. モーダルと背景のz-indexが逆になっている
  15. 15. 固定ヘッダーがモーダルより前にある
  16. 16. 疑似要素の重なり順が違う
  17. 17. flex/gridアイテムのz-indexを誤解している
  18. 18. 数字を大きくしすぎて管理できなくなっている
  19. 19. 検証ツールで親要素を見ていない
  20. 20. z-indexの最小テンプレート
  21. z-indexが効かないときの確認順
  22. まとめ

z-index を指定したのに前に出ない、重なり順が変わらない、モーダルがヘッダーの後ろに隠れる、というトラブルはよくあります。

z-index は数字だけで決まるわけではありません。position、親要素、stacking context、transformopacityoverflow などが関係します。

この記事では、z-indexが効かない原因を20個に分けて、確認順に解説します。

1. positionが指定されていない

z-indexが効かない原因で多いのが、position指定がないケースです。

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

まずは対象要素に position: relative; を付けて確認します。

2. z-indexがautoのままになっている

positionがあっても、z-index が指定されていなければ重なり順を明示できません。

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

重なり順を変えたい要素には、具体的な数値を指定します。

3. 親要素のz-indexが低い

子要素に大きな数字を指定しても、親要素自体が後ろにあると前に出られないことがあります。

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

.child {
  position: absolute;
  z-index: 9999;
}

子の 9999 より、親がどの重なり文脈にいるかが重要です。

4. 比べたい要素が別の親に入っている

z-indexは、ページ全体で単純に数字だけを比べるわけではありません。

<div class="area-a">
  <div class="child-a">A</div>
</div>
<div class="area-b">
  <div class="child-b">B</div>
</div>

別の親がstacking contextを作っている場合、子同士の数字だけでは比較できません。

5. 親にtransformが指定されている

transform は新しい重なりの文脈を作ることがあります。

.parent {
  transform: translateZ(0);
}

.child {
  position: absolute;
  z-index: 1000;
}

親に transform がある場合、子のz-indexが外側へ出られない原因になります。

6. 親にopacityが指定されている

opacity が1未満の要素も、stacking contextを作ります。

.parent {
  opacity: 0.99;
}

見た目のために少しだけ透明にした指定が、重なり順に影響することがあります。

7. filterやbackdrop-filterが指定されている

filterbackdrop-filter も重なりの文脈に影響します。

.parent {
  filter: drop-shadow(0 10px 20px rgba(0, 0, 0, 0.2));
}

ぼかしや影のための指定が、z-indexの効き方を変えることがあります。

8. isolation: isolate が指定されている

isolation: isolate; は、意図的に重なり文脈を分ける指定です。

.section {
  isolation: isolate;
}

便利な指定ですが、子要素を外側の要素より前に出したい場合は障害になることがあります。

9. mix-blend-modeが指定されている

mix-blend-mode もstacking contextに関係します。

.blend {
  mix-blend-mode: multiply;
}

合成表現を使っている要素周辺でz-indexが効かない場合は確認します。

10. fixed要素がtransformの親に閉じ込められている

親に transform があると、position: fixed; の見え方にも影響することがあります。

.wrapper {
  transform: translateZ(0);
}

.modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
}

モーダルは、できるだけbody直下など外側に置くと重なり順を管理しやすいです。

11. 同じz-indexなら後にある要素が前に出る

同じ重なり文脈でz-indexが同じ場合は、HTML上で後にある要素が前に出ます。

.box-a,
.box-b {
  position: relative;
  z-index: 1;
}

数字が同じなら、DOM順も確認します。

12. マイナスのz-indexで後ろに隠れている

z-index: -1; は、親や背景の後ろに隠れることがあります。

.bg {
  position: absolute;
  z-index: -1;
}

背景装飾で使う場合は、親要素の position や背景色も確認します。

13. overflowで切り取られている

z-indexが効いていても、親の overflow: hidden; で見切れることがあります。

.card {
  overflow: hidden;
}

.badge {
  position: absolute;
  top: -10px;
  right: -10px;
  z-index: 10;
}

「前に出ない」のではなく「切り取られている」可能性もあります。

14. モーダルと背景のz-indexが逆になっている

モーダルは、背景レイヤーより少し大きいz-indexにします。

.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: rgba(0, 0, 0, 0.5);
}

.modal {
  position: fixed;
  z-index: 1001;
}

背景と本体の数値を近くにして、役割を明確にします。

15. 固定ヘッダーがモーダルより前にある

ヘッダーのz-indexが高すぎると、モーダルより前に出ることがあります。

.header {
  position: sticky;
  top: 0;
  z-index: 100;
}

.modal {
  position: fixed;
  z-index: 1000;
}

ヘッダー、モーダル、通知など、役割ごとに段階を決めます。

16. 疑似要素の重なり順が違う

::before::after が文字の上にかぶることがあります。

.card {
  position: relative;
}

.card::before {
  position: absolute;
  inset: 0;
  z-index: 0;
  content: "";
}

.card-content {
  position: relative;
  z-index: 1;
}

装飾レイヤーより、本文レイヤーを前に出します。

17. flex/gridアイテムのz-indexを誤解している

flexやgridの子要素では、positionなしでもz-indexが効く場合があります。ただし親の文脈には影響されます。

.grid {
  display: grid;
}

.grid-item {
  z-index: 2;
}

効く場合と効かない場合を検証ツールで確認し、親のstacking contextも見ます。

18. 数字を大きくしすぎて管理できなくなっている

999999 のような値を増やすと、あとから破綻しやすくなります。

:root {
  --z-header: 100;
  --z-dropdown: 300;
  --z-modal: 1000;
  --z-toast: 1100;
}

役割ごとに段階を決めると、重なり順を管理しやすくなります。

19. 検証ツールで親要素を見ていない

z-indexの問題は、対象要素だけでなく親要素を見る必要があります。

  • 対象要素に position があるか
  • 親に transformopacity がないか
  • 親に z-index がないか
  • overflow で切り取られていないか
  • 同じ重なり文脈で比較されているか

検証ツールでは、親をたどって確認します。

20. z-indexの最小テンプレート

最後に、よく使う重なり順のテンプレートです。

:root {
  --z-base: 1;
  --z-header: 100;
  --z-dropdown: 300;
  --z-modal-backdrop: 900;
  --z-modal: 1000;
}

.header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
}

.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal-backdrop);
}

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

用途ごとに数値を決めておくと、後から数字を足し続けずに済みます。

z-indexが効かないときの確認順

  1. 対象要素に position があるか確認する
  2. 重ねたい相手と同じ親の中で比較されているか確認する
  3. 親要素に z-indextransformopacityfilter がないか見る
  4. overflow で切り取られていないか確認する
  5. 数字を大きくする前に、親の重なり順を確認する

まとめ

z-indexが効かないときは、数字だけではなく、position、親要素、stacking context、transformopacityoverflow を確認します。

positionの基本は CSSのpositionプロパティ、CSS全般が効かない場合は CSSが効かない原因まとめ を確認してください。