CSS 内の要素に z-index: 99999 を設定したことがあり、それが他の要素の上に表示されなかったことがありますか?すべてのさまざまな要素がより低い値に設定されているか、まったく設定されていないと仮定すると、値がこれほど大きい場合、その要素は視覚的に他の要素の上に簡単に配置されます。 通常、Web ページは 2 次元空間で表現されます。ただし、特定の CSS プロパティを適用すると、奥行きを伝えるために仮想の Z 軸平面が導入されます。この平面は画面に対して垂直であり、ユーザーはそこから要素が重なり合っている順序を認識します。仮想の Z 軸、つまり積み重ねられた要素に対するユーザーの認識の背後にある考え方は、それを作成する CSS プロパティが結合して、いわゆる積み重ねコンテキストを形成するというものです。 Web ページ上で要素がどのように「スタック」されるか、スタック順序を制御するもの、および必要に応じて要素を「アンスタック」するための実際的なアプローチについて説明します。 コンテキストのスタッキングについて Web ページを机として想像してください。 HTML 要素を追加するときは、机の上に紙を次々と並べることになります。最後に配置された紙は、最後に追加された HTML 要素に相当し、その前に配置された他のすべての紙の上に配置されます。これは、ネストされた要素であっても、通常のドキュメント フローです。デスク自体は、他のすべてのフォルダーを含む 要素によって形成されるルート スタッキング コンテキストを表します。 ここで、特定の CSS プロパティが機能します。 位置 (Z インデックス付き)、不透明度、変換、包含などのプロパティはフォルダーのように機能します。このフォルダーは、要素とそのすべての子を取得し、メイン スタックから抽出して、それらを別のサブスタックにグループ化し、いわゆるスタッキング コンテキストを作成します。位置決めされた要素の場合、auto 以外の z-index 値を宣言すると、これが発生します。不透明度、変換、フィルターなどのプロパティの場合、特定の値が適用されるとスタッキング コンテキストが自動的に作成されます。
これを理解してください。紙片 (つまり、子要素) がフォルダー (つまり、親のスタッキング コンテキスト) 内にあると、そのフォルダーから出たり、別のフォルダー内の紙の間に配置したりすることはできません。その z-index は、独自のフォルダー内でのみ関連するようになりました。
下の図では、用紙 B はフォルダー B のスタッキング コンテキスト内にあり、フォルダー内の他の用紙と一緒にのみ注文できます。
机の上に 2 つのフォルダーがあると想像してください。
.folder-a { z-index: 1; } .folder-b { z-index: 2; }
マークアップを少し更新してみましょう。フォルダー A の内部は特別なページ、z-index: 9999 です。フォルダー B の内部は通常のページ、z-index: 5 です。
.special-page { z-index: 9999; } .plain-page { z-index: 5; }
どのページが一番上ですか? これはフォルダー B の .plain-page です。ブラウザーは子ペーパーを無視し、2 つのフォルダーを最初に積み重ねます。 2 が 1 より大きいことがわかっているため、フォルダー B (z-index: 2) が認識され、フォルダー A (z-index: 1) の上に配置されます。一方、z-index: 9999 ページに設定された .special-page は、z-index が可能な限り高い値に設定されているにもかかわらず、スタックの一番下にあります。 スタッキングコンテキストをネストして (フォルダー内にフォルダーを)、「ファミリーツリー」を作成することもできます。同じ原則が当てはまります。子は親のフォルダーから逃れることはできません。 スタッキング コンテキストがレイヤーをグループ化して並べ替えるフォルダーのようにどのように動作するかが理解できたので、次に、なぜ変換や不透明度などの特定のプロパティが新しいスタッキング コンテキストを作成するのかを尋ねる価値があります。 ここで重要なのは、これらのプロパティは、見た目のせいでスタッキング コンテキストを作成するわけではありません。これは、ブラウザが内部でどのように動作するかによって行われます。変換、不透明度、フィルター、遠近法を適用すると、ブラウザーに「この要素は移動、回転、またはフェードする可能性があるので、準備をしておいてください!」と伝えていることになります。
これらのプロパティを使用すると、ブラウザーはレンダリングをより効率的に管理するために新しいスタッキング コンテキストを作成します。これにより、ブラウザーはアニメーション、変換、視覚効果を独立して処理できるようになり、これらの要素がページの残りの部分とどのように相互作用するかを再計算する必要が減ります。これは、ブラウザーが「このフォルダーを個別に処理するので、フォルダー内の何かが変更されるたびにデスク全体を再配置する必要がなくなります。」と言っていると考えてください。 しかし、そこには副作用。ブラウザが要素を独自のレイヤーに移動したら、その中のすべてを「フラット化」して、新しいスタッキング コンテキストを作成する必要があります。それは、フォルダーを机から取り出して個別に処理するようなものです。そのフォルダー内のすべてがグループ化され、ブラウザーは、何を上に置くかを決定するときに、フォルダーを 1 つのユニットとして扱います。 したがって、transform プロパティと opacity プロパティは要素の視覚的なスタック方法に影響を与えていないように見えますが、実際には影響を与えており、パフォーマンスを最適化するためのものです。他のいくつかの CSS プロパティも同様の理由でスタッキング コンテキストを作成できます。さらに詳しく知りたい場合は、MDN に完全なリストが用意されています。かなりの数がありますが、これは、知らずに誤ってスタッキング コンテキストを作成してしまうことがいかに簡単であるかを示しているだけです。 「アンスタッキング」問題 スタックの問題はさまざまな理由で発生する可能性がありますが、他の理由よりも一般的なものもあります。モーダル コンポーネントは、他のすべての要素の上の最上位レイヤーでコンポーネントを「開く」ように切り替え、「閉じた」ときに最上位レイヤーからコンポーネントを削除する必要があるため、古典的なパターンです。 モーダルを開いたにもかかわらず、何らかの理由でモーダルが表示されないという状況に誰もが遭遇したことがあると思います。正しく開かなかったのではなく、スタッキング コンテキストの下位層で表示されなくなっているのです。 これでは「どうして?」と不思議に思うでしょう。設定してから:
.overlay { 位置: 固定; /* スタッキングコンテキストを作成します */ z インデックス: 1; /* 要素を他のすべての上のレイヤーに配置します */ インセット: 0; 幅: 100%; 高さ: 100vh; オーバーフロー: 非表示; 背景色: #00000080; }
これは正しいように見えますが、モーダル トリガーを含む親要素が、やはり z-index: 1 に設定されている別の親要素内の子要素である場合、技術的にはメイン フォルダーによって隠されたサブレイヤーにモーダルが配置されます。その特定のシナリオと、その他のスタッキング コンテキストの一般的な落とし穴をいくつか見てみましょう。スタッキング コンテキストを誤って簡単に作成してしまうだけでなく、それをいかに誤って管理するかについても理解できると思います。また、どのように管理状態に戻すかは状況によって異なります。 シナリオ 1: 閉じ込められたモーダル
モーダルが低レベル層にトラップされていることがすぐに確認でき、親を特定できます。 ブラウザ拡張機能 賢明な開発者は、役立つ拡張機能を構築しました。この「CSS Stacking Context Inspector」Chrome 拡張機能のようなツールは、DevTools に追加の z-index タブを追加して、スタッキング コンテキストを作成する要素に関する情報を表示します。
IDE 拡張機能 VS Code 用のこのような拡張機能を使用すると、開発中に問題を発見することもできます。これにより、潜在的なスタッキング コンテキストの問題がエディターで直接強調表示されます。
スタックを解除して制御を取り戻す 根本原因を特定したら、次のステップはそれに対処することです。この問題に対処するにはいくつかのアプローチがありますので、順番にリストしていきます。ただし、どのレベルの人でも選択できます。誰も他の人に文句を言ったり妨害したりすることはできません。 HTML構造を変更する これは最適な修正と考えられます。コンテキストの重なりの問題が発生するには、HTML 内のおかしな位置にいくつかの要素を配置している必要があります。ページを再構築すると、DOM の形状を変更し、コンテキストの積み重ねの問題を解決できます。問題のある要素を見つけて、HTML マークアップのトラップ要素から削除します。たとえば、最初のシナリオ「トラップされたモーダル」は、.modal-container をヘッダーの外に移動し、単独で
要素に配置することで解決できます。<ヘッダークラス="ヘッダー">
ヘッダー
ヘッダ> <メインクラス="コンテンツ">メインコンテンツ
このコンテンツの Z インデックスは 2 ですが、モーダルはまだカバーされません。
メイン>
モーダルタイトル
今、私は何も遅れていません。 DOM の再構築の結果、より良い立場になりました。
「モーダルを開く」ボタンをクリックすると、モーダルが他のすべての前に配置されます。 Shoyombo Gabriel Ayomide によるペン シナリオ 1: トラップされたモーダル (ソリューション) [フォーク] を参照してください。 を調整しますCSS での親スタッキングコンテキスト レイアウトを壊さずに移動できない要素の場合はどうなるでしょうか?この問題に対処する方が良いでしょう。親がコンテキストを確立します。コンテキストのトリガーに関与する CSS プロパティ (複数可) を見つけて、それを削除します。目的があり、削除できない場合は、親要素にその兄弟要素よりも高い z-index 値を与えて、コンテナ全体を持ち上げます。 z-index 値が高くなると、親コンテナが一番上に移動し、その子がユーザーの近くに表示されます。 「ドロップダウンが沈む」シナリオで学んだことに基づくと、ドロップダウンをナビゲーションバーの外に移動することはできません。それは意味がありません。ただし、.navbar コンテナの z-index 値を、.content 要素の z-index 値よりも大きくすることができます。 .navbar { 背景: #333; /* z インデックス: 1; */ z インデックス: 3; 位置: 相対的; }
この変更により、.dropdown-menu が問題なくコンテンツの前に表示されるようになりました。 Shoyombo Gabriel Ayomide によるペン シナリオ 2: The Submerged Dropdown (Solution) [フォーク] を参照してください。 フレームワークを使用している場合はポータルを試してください React や Vue などのフレームワークでは、ポータルは、DOM 内の通常の親階層の外にあるコンポーネントをレンダリングできるようにする機能です。ポータルは、コンポーネントのテレポート デバイスのようなものです。これらを使用すると、コンポーネントの HTML をドキュメント内の任意の場所 (通常は document.body 内) にレンダリングできると同時に、props、state、event の元の親との論理的な接続を維持できます。これは、レンダリングされた出力が文字通り問題のある親コンテナーの外側に表示されるため、スタッキング コンテキスト トラップをエスケープするのに最適です。 ReactDOM.createPortal( <ツールチップ />、 文書.本文 );
これにより、親にオーバーフローがある場合でも、ドロップダウン コンテンツが親の背後に隠れることがなくなります。つまり、非表示または Z インデックスが低い場合でも同様です。 前に説明した「クリップされたツールチップ」シナリオでは、ポータルを使用して、ツールチップをドキュメント本文に配置し、コンテナー内のトリガーの上に配置することで、オーバーフロー: 非表示のクリップからツールチップを救出しました。 Shoyombo Gabriel Ayomide によるペンのシナリオ 3: クリップされたツールチップ (ソリューション) [フォーク] を参照してください。 副作用のないスタッキングコンテキストの導入 前のセクションで説明したすべてのアプローチは、問題のあるスタッキング コンテキストから要素を「アンスタッキング」することを目的としていますが、実際にスタッキング コンテキストを作成する必要がある、または作成したい状況がいくつかあります。 新しいスタッキング コンテキストを作成するのは簡単ですが、すべてのアプローチには副作用が伴います。つまり、isolation を使用する場合を除いて、isolate です。要素に適用されると、その要素の子のスタッキング コンテキストは、その外部の要素の影響を受けるのではなく、各子とそのコンテキスト内で相対的に決定されます。典型的な例は、その要素に z-index: -1 などの負の値を割り当てることです。 .card コンポーネントがあると想像してください。 .card のテキストの後ろ、カードの背景の上に装飾的な図形を追加したいと考えています。カードにスタッキング コンテキストがない場合、z-index: -1 はシェイプをルート スタッキング コンテキストの一番下 (ページ全体) に送信します。これにより、.card の白い背景の後ろに消えます。 Shoyombo Gabriel Ayomide による Pen Negative z-index (問題) [フォーク] を参照してください。 これを解決するには、親の .card で isolate: isolate を宣言します。 Shoyombo Gabriel Ayomide による Pen Negative z-index (solution) [forked] を参照してください。 これで、.card 要素自体がスタッキング コンテキストになります。その子要素 (:before 擬似要素上に作成された装飾図形) の z-index: -1 が設定されている場合、親要素のスタッキング コンテキストの一番下に移動します。意図したとおり、テキストの後ろとカードの背景の上に完璧に配置されます。 結論 次回 Z インデックスが制御不能になったように見えるときは、スタック コンテキストが閉じ込められているということを覚えておいてください。 参考文献
スタッキングコンテキスト (MDN) Z インデックスとスタッキング コンテキスト (web.dev) 「CSS の分離プロパティを使用して新しいスタッキング コンテキストを作成する方法」、Natalie Pina 「一体、z-index って何??」、ジョシュ・コモー
SmashingMag の続きを読む
「大規模プロジェクトにおける CSS Z-Index の管理」、Steven Frieson 「スティッキーヘッダーとフルハイト要素: トリッキーな組み合わせ」フィリップ・ブローネン 「コンポーネントベースの Web アプリケーションでの Z インデックスの管理」、Pavel Pomerantsev 「Z-Index CSS プロパティ: 包括的な外観」、Louis Lazaris