モーダルが背面のヘッダーに隠れる。ドロップダウンが隣のカードの下に潜る。z-index: 9999 を書いても変わらない。そこで 99999 にしてみる——この手順を踏んだことがあるなら、たいてい問題は数字の側にありません。
解くべき問いは「いくつにするか」ではなく、「この要素はどの積み重ね文脈に属しているか」です。この記事では、その文脈がどこで生まれ、どう点検するかを、出典にあたりながら順に見ていきます。
参照したのは、MDN の Stacking context(ページ上の最終更新 2026年9月28日)と、CSS 2.2 の Appendix Eです。
30秒で要点
- z-indexはページ全体の順位ではなく、同じスタッキングコンテキスト内の兄弟同士の順位としてしか比較されない
- 入れ子になったスタッキングコンテキストは、親から見ると分解されない1個の塊として扱われる。だから中の子の値をいくら大きくしても、外側の要素を越えられない
- スタッキングコンテキストを作る条件はpositionとz-indexだけではなく、
opacityが1未満・transform系・filter系・isolation・will-change・contain・container-type・トップレイヤーなど多数ある z-index: autoとz-index: 0は見え方が同じでも意味が違う。autoは子を閉じ込めず、0は原子的な文脈を作る- 点検の順序は「祖先をたどって文脈を作っている宣言を探す → その宣言が必要かを判断する → 必要なら構造を変える」。数字を上げるのは最後
z-indexの数字は、何に対する数字なのか
まず、この値が何を表しているかを定義し直します。
z-indexは単位のない整数で、値そのものに絶対的な意味はありません。意味を持つのは比較だけです。そして比較の範囲が、この記事の主題にあたります。
MDNは次のように記述しています。スタッキングコンテキストの内部では、子要素は兄弟要素すべてのz-index値に従って積み重ねられる。そして入れ子になった要素のスタッキングコンテキストは、その親の中でしか意味を持たない。
Within a stacking context, child elements are stacked according to the
z-indexvalues of all the siblings. The stacking contexts of these nested elements only have meaning in this parent.
ここで言うスタッキングコンテキスト(積み重ねの文脈。要素のまとまりの中で「誰が手前か」を内側だけで決着させる入れ物)が、比較の範囲を区切ります。つまりz-indexの分母は「ページ全体」ではなく「自分が属するスタッキングコンテキストの中にいる兄弟の集合」です。9999という数字は、その集合の外には届きません。
入れ子の文脈は、親から見ると1個の塊になる
ここが「効かない」の正体です。MDNは、各スタッキングコンテキストは自己完結していると述べ、要素の内容が積み重ねられた後は、その要素全体が親のスタッキングコンテキストにおける1個の単位として扱われると書いています。
Each stacking context is self-contained. After an element's contents are stacked, the entire element is considered as a single unit in the stacking order of its parent stacking context.
さらに、入れ子の文脈は親のスタッキングコンテキストの中で原子的に(atomically)1個の単位として扱われ、ある文脈の内部の要素はその外側の要素とは独立に積み重ねられるとも記述されています。
この「原子的」という語が効いています。親から見たとき、入れ子の文脈は中身を開いて比較してもらえません。箱の中で誰が一番手前かは箱の中の話で、箱そのものがどこに置かれるかは、箱の外の順序で決まる。
だから「モーダルのz-indexを上げても、固定ヘッダーの下に潜ったまま」という状況が起きます。モーダルが属している箱が、ヘッダーより奥に置かれているなら、箱の中で何を書いても結果は変わりません。
文脈を作るのはpositionとz-indexだけではない
次に詰まるのは、「その箱はどこで生まれたのか」です。position指定とz-indexの組み合わせだけを疑っていると、見つかりません。
MDNの「Features creating stacking contexts」の一覧を2026年10月12日に確認した時点では、次のとおりです。
- ルート要素(
<html>) positionがabsoluteまたはrelativeかつz-indexがauto以外の要素positionがfixedまたはstickyの要素container-typeがsizeまたはinline-sizeの要素z-indexがauto以外のフレックスアイテムz-indexがauto以外のグリッドアイテムopacityが1未満の要素mix-blend-modeがnormal以外の要素- 次のいずれかが
none以外の要素——transform/scale/rotate/translate/filter/backdrop-filter/perspective/clip-path/mask(mask-image・mask-borderを含む) isolationがisolateの要素will-changeに「初期値以外でスタッキングコンテキストを作るプロパティ」を指定した要素containがlayoutまたはpaint、あるいはそれらを含む複合値(contain: strict・contain: content)の要素- トップレイヤーに配置された要素とその
::backdrop(フルスクリーン・ポップオーバーなど) - スタッキングコンテキストを作るプロパティを
@keyframesでアニメーションし、animation-fill-mode: forwardsを指定した要素
実務で見落としやすいのは、重なり順と関係がなさそうな宣言です。フェードインのための opacity: 0.99、ちらつき対策の transform: translateZ(0)、スクロール最適化の will-change、カード内のレイアウト制御の contain ——どれも見た目を整えるために書いた宣言ですが、結果として箱を1つ増やしています。なおこの一覧は上記の確認時点のものなので、重要な判断の前には原典を開き直してください。
z-index: auto と z-index: 0 は、見え方が同じでも意味が違う
実務でよくあるのが「念のため z-index: 0 を書いておく」です。見た目の重なり順は auto のときと変わらないので、無害に見えます。しかし仕様の扱いは別です。
CSS 2.2 Appendix E の描画順の記述では、z-index: auto または 0 を持つすべての位置指定子孫がツリー順で描かれるとした上で、両者を分けています。auto の場合は「新しいスタッキングコンテキストを作ったものとして扱うが、位置指定された子孫および実際に新しいコンテキストを作る子孫は、親のコンテキストに属するものとみなす」。z-index: 0 の場合は「生成されたスタッキングコンテキストを原子的に扱う」。
For those with 'z-index: auto', treat the element as if it created a new stacking context, but any positioned descendants and descendants which actually create a new stacking context should be considered part of the parent stacking context, not this new one. For those with 'z-index: 0', treat the stacking context generated atomically.
言い換えると、auto は子を閉じ込めず、0 は閉じ込めます。だから「見え方は変わらないから安全」と思って書いた 0 が、その内側にある要素の比較範囲を切り離すことがあります。なお位置指定レイアウトの仕様はその後も整理が進んでいるため、本記事は出典をCSS 2.2 Appendix Eに限定して扱います。
描画順は階層的に決まっている
CSS 2.2 Appendix E の "Painting order" は、描画の順序を階層的に規定しています。確認できた範囲での大枠は次の順です。
- ルート要素の背景
- 負のz-index(0を除く)を持つ位置指定子孫のスタッキングコンテキスト(最も負のものが先、同値はツリー順)
- 通常フローの、位置指定されていないブロックレベル子孫
- 位置指定されていない浮動子孫
- インラインコンテンツ
z-indexがautoまたは0の位置指定子孫(ツリー順)z-indexが1以上の位置指定子孫(小さい順、同値はツリー順)
読み取っておきたいのは、「位置指定されていない通常フローの要素」が、負のz-indexより手前で、正のz-indexより奥に入るという点です。z-index: -1 を書いた要素が背景に沈んで見えなくなるのは、この順序の帰結です。細部(テーブルの描画や双方向テキストなどの例外)に踏み込む場合は原典を直接参照してください。
なぜz-indexが「全体の優先度」に見えるのか
ここまでの構造を知っていても、最初に 9999 を試してしまうのはなぜか。読者がこの誤解をしやすい理由は、小さいページでは実際にそう振る舞ってしまうところにあります。
スタッキングコンテキストがページに1つしかない間は、すべての位置指定要素が同じ兄弟集合に属します。この状態では、数字の大小だけで重なり順をきれいに説明できます。つまりz-indexを学び始めた時期の経験は、「数字はグローバルな優先度である」という理解を裏切らないのです。
誤解が顔を出すのは、コンポーネント分割が進み、アニメーションや固定ヘッダーや contain が入ってからです。そのときすでに「数字を上げれば前に来る」という理解は何十回も成功しています。成功体験で裏打ちされた誤解は、反証が来たときに「数字が足りない」と解釈される。 これが、桁を増やす方向に手が伸びる理由だと考えられます。
直し方の順序——数字を上げるのは最後
点検の手順として、次の順序を提案します。
- 問題の要素から祖先をたどる。 開発者ツールで親・祖父・それ以上を順に見て、上の一覧にある宣言を探します。
opacity・transform・filter・will-change・contain・isolation・position+z-indexが主な容疑者です - 見つけた宣言が必要かを判断する。 ちらつき対策で入れた
transform: translateZ(0)が今も必要か、opacity: 0.99に意図があるか。不要なら外す。これが最も影響範囲の小さい修正です - 必要なら構造側を変える。 宣言を残すなら、重ねたい要素をその箱の外に出します。DOM(ブラウザが読み込んだHTMLの構造)上の位置を変える、トップレイヤー(フルスクリーンやポップオーバーの仕組み)に載せる、といった選択です
- 最後に数字を調整する。 同じ箱の中にいる兄弟との順位を決める段階になって初めて、z-indexの値が効きます
この順序の要点は、1〜3を飛ばして4から入ると、効かない上に原因が隠れるところです。数字を上げた記述が残ると、次に読む人は「ここは数字で制御されている」と読みます。
なお、「z-indexは10刻みで設計する」といった数値の運用指針は、本記事が参照した資料に根拠がありません。慣習として採る判断はありえますが、仕様の要請ではないため、ここでは扱いません。
確かなことと、まだ確かではないこと
確かなこと: z-indexの比較が同一スタッキングコンテキスト内の兄弟に限られること。入れ子の文脈が親から見ると原子的な1単位として扱われること。文脈を作る条件が本文の一覧のとおり多数あること(2026年10月12日にMDNで確認)。z-index: auto と 0 の扱いがCSS 2.2 Appendix Eで区別されていること。
まだ確かではないこと: ブラウザ間の実装差。本記事が参照した2つの資料はいずれも実装差を扱っておらず、実機での比較も行っていません。また will-change や contain の個別の値がいつ文脈を生むかという網羅的な挙動は、一覧に書かれた範囲を超えて確認していません。
自分の画面で試せる、最小の検証
いま手元に「z-indexが効かない要素」があるなら、1分で確かめられます。
開発者ツールでその要素を選び、祖先を1つずつ上にたどって opacity・transform・filter・will-change・contain・isolation、そして position と z-index の組み合わせを探してください。見つかったら、その宣言を一時的に無効化して、重なり順が変わるかを見ます。
変わったなら、原因はその箱です。変わらなかったなら、さらに上に箱があります。数字を1桁増やすより、この往復のほうが早く終わる——それを確認するための検証です。
重なり順で迷ったときに戻る3つの問い
- この要素は、どの箱の中にいるか。 答えられないうちは、数字の議論に入れません
- その箱は、なぜそこにあるか。 重なり順のために作られた箱はまれで、たいていは別の目的の宣言の副産物です
- この数字は、誰と比べた数字か。 比べる相手を言えない値は、次に読む人を誤解させます
重なり順の問題は、個別の修正で消しても別の場所で再発します。コンポーネントの境界と宣言の置き場所をどう決めるかという話に接続するため、デザインシステム構築ガイドと、画面幅ごとの出し分けで要素の前後が変わる場面を扱ったレスポンシブデザイン実践ガイドも合わせて読むと、どこで決着させるかの見当がつきやすくなります。
この記事で扱ったような判断を、自社の状況に照らして整理したい場合は、無料診断ツールで状況を言語化するところから始めることができます。
状況を整理する(15分)