Webサイト・WebアプリのHTML要素のスタイリングにおいて、z-indexを利用して要素を重ね合わせることをよくやる。
ただ、トラブルもよく見る。最近見た深刻な例では、UIコンポーネントをオーバーレイしてモーダルダイアログを表示させたいケースで、あるべきz-indexの指定がないゆえにダイアログがでず、ユーザが操作不能になるケースがあった。
このようなケースで起きたことを正しく理解するには、Stacking ContextとHTMLの出現順がZ軸のスタイリングにどう作用するのかを知っておく必要がある。
そこでこれらについて整理することにした。
HTMLの出現順によるZ軸のスタイル
基本的には、後から出現した要素が手前に配置される。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
p {
position: absolute;
background-color: #fff;
}
</style>
</head>
<body>
<p>one</p>
<p>two</p>
<p>three</p>
</body>
</html>
Stacking Contextが発生する場合
出現順と別軸で、次の条件に沿う要素が生成された場合、Stacking Contextという制御単位が生成され、単位内でz-indexの値によって、重なり順を制御できる。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.container {
position: relative;
}
p {
position: absolute;
background-color: #fff;
}
p:nth-child(1) {
z-index: 3;
}
p:nth-child(2) {
z-index: 2;
}
p:nth-child(3) {
z-index: 1;
}
</style>
</head>
<body>
<div class="container">
<p>one</p>
<p>two</p>
<p>three</p>
</div>
</body>
</html>
Stacking Contextは階層化でき、子要素がより手前に配置される
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.container {
position: relative;
}
.inner {
position: relative;
}
p {
position: absolute;
background-color: #fff;
}
p:nth-child(1) {
z-index: 3;
}
p:nth-child(2) {
z-index: 2;
}
p:nth-child(3) {
z-index: 1;
}
</style>
</head>
<body>
<div class="container">
<p>one</p>
<p>two</p>
<div class="inner">
<p>three</p>
</div>
</div>
</body>
</html>
z-indexの設定値をどう決めるか
z-indexは重なり順を制御するものであるから、そもそもの目的に対して考えてみると、z-indexを使わずに済むならそれが一番望ましい。それを前提とすると、
- セットしないで済む方法を考える
- HTMLの登場順や、新しいスタッキングコンテキストの生成で同じ結果にできるならそれがベスト
- スタッキングコンテキストの生成で済む方法を考える
- 既存のポリシーと整合する値を考える
- 一貫性のある設定値を利用する。
- 例えば・・・
- 背景:z-index: -1
- 基準:z-index: 0
- はみ出し(ネガティブマージン等):z-index: 10
- モーダル:z-index: 100
- スマホメニュー:1000
- なるべく既存のCSS変数、設定値と同じもので済む方法を考える
- 例えば・・・
- 背景:z-index: var(–z-back)
- 基準:z-index: var(–z-base)
- はみ出し(ネガティブマージン等): z-index: var(–z-xxx)
- モーダル:z-index: var(–z-modal)
- スマホメニュー:z-index: var(–z-spmenu)
- 例えば・・・
周囲のフィードバック
勉強会で得た学びは次の通り。
- UIフレームワークを利用することで、問題が発生することを避けやすくなるかも
- ヘッダーはstickyを利用する、オーバーレイしたいところはfixedにするなど、明示的に設定するとよさそう