疑似要素とz-indexの重なり制御:基礎と具体例
スタッキングコンテキストと疑似要素の基礎知識
スタッキングコンテキストとは、要素同士の重なり順(Z軸方向の奥行き)を管理する独立した描画レイヤーのようなものです。ある要素がスタッキングコンテキストを形成すると、その子孫要素同士は親要素内でのみ重なり順を比較し、親コンテキストの他要素とは独立して扱われます。
親コンテキストに対しては、スタッキングコンテキスト全体が一つの要素として扱われるため、中の子要素がいくら高いz-indexを持っていても外部の要素を飛び越えて表示されることはありません(親要素のスタック内で完結するため)。例えば、親要素にz-index:1を設定しその中の子要素にz-index:530000を設定しても、親要素の外では「1」として扱われるため、外部のz-index:5の要素にも負けて下に配置されます。
z-indexが効かない主な原因
1. positionプロパティの未設定
要素にpositionが指定されていない(staticのまま)場合、z-indexを指定しても効果がありません。まず対象要素(または疑似要素の親)にposition: relativeやabsoluteなどを設定しているか確認してください。例として、ボタンにマスクを重ねる場合はボタン要素にposition: relative;を付与する必要があります。
2. スタッキングコンテキストの発生
祖先要素のいずれかにスタッキングコンテキストを形成する条件があると(例: positionがstatic以外かつz-index指定、opacity<1、transformの指定など)、その内側では新しい重なりコンテキストが生まれます。これにより、意図しない重なり順序になることがあります。典型例として、CSSのtransformを適用すると要素が新規スタッキングコンテキストを作るため、兄弟要素同士でz-index比較ができず、どんなにz-indexを上げても他の兄弟要素の上に来なくなる場合があります。同様にopacityやfilter等のプロパティでもスタックが分離します。
3. HTMLの構造(要素の出現順)
同じスタッキングコンテキスト内では、特別な指定がない限り後に書かれた要素が手前に表示されます。疑似要素も「要素の前後」に挿入されるため、::before疑似要素は基本的に本体コンテンツより先に描画され(後から来る本体より下になり)、::after疑似要素は本体の後に描画されるためコンテンツより上に重なります。この性質を利用すると、単に疑似要素の種類を変えるだけで重なり順を変えられることがあります。
4. 疑似要素とスタックの関係
::beforeや::afterの疑似要素は、実際にはその親要素の「子要素」として扱われます。これは重要なポイントです。
簡単に言うと:
- 疑似要素は親要素の中に存在する
- 親要素の中での重なり順は、疑似要素自身のz-indexで制御できる
- しかし、親要素が他の要素と重なる場合、疑似要素は親要素の重なり順に従う
例えば、ボタン(親要素)に対して::after疑似要素でマスクを作った場合:
- マスクとボタンのテキストの前後関係は、疑似要素のz-indexで調整できる
- しかし、そのボタンと他のボタンとの重なり順は、親ボタン要素のz-indexで決まる
- 親ボタンがスタッキングコンテキストを形成している場合(z-indexやtransformなどを持つ場合)、その中の疑似要素は「外の世界」と直接z-index比較されない
これが「疑似要素が親要素のスタッキングコンテキスト内に閉じ込められる」という意味です。
実装パターンと注意点
1. ボタンに対してマスクを重ねる場合
ボタン上に半透明のマスクをかけて無効化表示にしたり、ホバー時のオーバーレイ効果を出したりするケースです。この場合、ボタン要素に対して疑似要素を用いて覆い被せる実装がよく行われます。
典型的な実装方法:
.btn {
position: relative;
}
.btn::after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
}
z-indexが意図通り効かない原因:
- 親要素や疑似要素のスタック設定ミス – しばしば起きるのが、ボタン要素(親)に不要なz-indexを指定してスタッキングコンテキストを作ってしまい、疑似要素が親の背景の後ろに回り込めなくなるケースです。
- 疑似要素の種類と順序 – マスクを前面に出したいのに::beforeを使ったためにボタンのテキストやアイコンの下に敷かれてしまう場合があります。
- positionの指定漏れ – 疑似要素にposition: absoluteを指定しても、親側がposition: staticのままだとボタンを基準に配置されません。
2. 背景画像の上に疑似要素を重ねる場合
要素にCSSの背景画像を設定し、その上にカラーフィルターやグラデーションのオーバーレイを重ねたい場合にも疑似要素が活躍します。
典型的な実装方法:
.banner {
position: relative;
background-image: url('image.jpg');
}
.banner::after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255,0,0,0.5);
}
z-indexが意図通り効かない原因:
- 疑似要素の順序による問題 – 背景画像を覆うには本来::afterを使うのが簡単ですが、::beforeを使った場合、デフォルトではその疑似要素が背景画像の下に潜ってしまう可能性があります。
- positionやサイズ指定の漏れ – 親要素にposition: relativeを指定し忘れると、疑似要素がページ全体に表示されたり位置がずれたりします。
- スタッキングコンテキストの干渉 – 背景画像のコンテナの親要素にtransformやopacityが指定されていると、新たなスタックができている可能性があります。
3. モーダルウィンドウやポップアップ内で疑似要素を使う場合
モーダル(ポップアップ)では、画面全体を暗くするオーバーレイや吹き出しの三角形などに疑似要素が使われます。
背景オーバーレイに疑似要素を使う:
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1000;
}
.modal::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 0;
}
.modal-content {
position: relative;
z-index: 1;
}
z-indexが意図通り効かない原因:
- 親要素のスタッキングコンテキストに閉じ込められる – モーダル自体をページ上部に表示したいのに、実装上モーダルの親に当たる要素にスタッキングコンテキストがあると、モーダルのz-indexをいくら高くしても親要素より前面に出せません。
- 疑似要素のz-index設定ミス – 背景オーバーレイを疑似要素で実現する場合、誤って::afterで実装するとダイアログ内容より前面に出てしまい、中身が見えなくなる失敗がありえます。
- 固定定位要素と変形プロパティ – モーダルは通常position: fixedで実装しますが、親要素にtransformが指定されていると、その親が基準のスタックになってしまいます。
複雑なレイアウトで疑似要素を安全に使うベストプラクティス
1. スタッキングコンテキストの理解と確認
まず、どの要素がスタッキングコンテキストを形成しているかを把握しましょう。開発者ツールを使えば要素に適用中のpositionやtransform、opacityなどが確認できます。
2. 必要最小限のpositionとz-index指定
z-indexは強力ですが乱用せず、必要なところにだけ付けます。特に親子関係で安易に親にz-indexを与えないよう注意します。
3. :beforeと:afterの使い分け
疑似要素は用途によって使い分けましょう。装飾的な要素や前面に出したいもの(アイコンや上掛けのエフェクト)は::afterを使うと、デフォルトでコンテンツより上に来るので制御が簡単です。背景的な要素や下敷きにしたいもの(下線や背面の飾り)は::beforeを使えば通常コンテンツより下に配置されます。
4. 重なり順のテスト
複雑なレイアウトでは、小さな変更で重なり順が変化することがあります。疑似要素を追加したら、各ブラウザで実際に表示を確認し、想定外にどれかが前後していないかテストします。
まとめ
スタッキングコンテキストによる重なり順の変化を理解することが重要です。例えば、親要素にz-index:1を設定し、その内部の子要素にz-index:530000を指定しても、親要素の外では「1」として扱われるため、外部のz-index:5の要素の方が前面に表示されます。このように、大きなz-indexを指定しても親コンテキスト次第で順序が逆転しうる点に留意しましょう。
疑似要素とz-indexを扱う際は:
- 要素の配置(position指定)と順序を正しく設定し
- スタッキングコンテキストの仕組みを理解して不要なコンテキストを作らないようにし
- 意図しない重なりが発生した場合は親要素から子要素までのz-indexと特殊プロパティ(transformやopacity等)をチェックすること
が安全に使うための基本原則です。これらを踏まえてコーディングすれば、複雑なレイアウトでも疑似要素のレイヤー制御を思い通りに行えるでしょう。