🗂️
[CSS設計] 破綻しにくいz-indexの指定を考える
概要
各コンポーネントに指定するz-index
の値を定義する。
モチベーション
-
z-index
の衝突を避けたい -
z-index
の指定を理由を明確にしたい - コンポーネントが増えるたびに
z-index
の定義を増やしたくない
前提知識
重ね合わせコンテキスト(スタッキングコンテキスト)という概念があることを前提に話を進めるため、以下のページを合わせて読むと理解がしやすい。
z-index
のルール
複雑さを避けるため以下のルールを設ける。
- 各コンポーネント内の
z-index
指定を極力少なくする -
z-index
は0
から4
までの値を使用する(後述のLayer Stackに基づく指定をする)-
-1
などの負数は使用しない - 数値を飛び抜かして指定をしない
-
Layer Stack のルール
- コンポーネントが持つべき
z-index
の値を役割ごとにレイヤー(階層)上に定義する - 階層が重なるにつれて
z-index
の値を増やしていく
z-index: 4
Layer Stack 4 : いかなる状態でも上に配置される要素。主に以下のようなコンポーネントを想定している。
- モーダル
- ドロワー
- オーバーレイ
z-index: 3
Layer Stack 3 : 常に上に配置されるような要素。Layer Stack 4(モーダルなど)よりは下の層に位置するが、コンテンツよりは上に位置するコンポーネント。
- グローバルヘッダー(例: スクロールで追随する固定ヘッダー)
z-index: 2
Layer Stack 2 : - ツールチップ
- ポップオーバー
- フローティングボタン(例: カルーセルなどの矢印ボタン)
z-index: 1
Layer Stack 1 : スタックを持たない要素の上に配置される。
- バッジ
z-index
の定義
:root {
--layer-stack-1: 1;
--layer-stack-2: 2;
--layer-stack-3: 3;
--layer-stack-4: 4;
}
.modal {
z-index: var(--layer-stack-4);
}
.modal-in-modal {
z-index: calc(var(--layer-stack-4) + 1);
}
isolation
のルール
Layer Stack の定義だけだとコンポーネント同士でz-index
が競合し、意図しない重なりになってしまうケースも考えられる。その場合、isolation
を利用してコンポーネントのルートにスタッキングコンテキストを生成させることで問題を解決することができる。
.special-components {
isolation: isolate; /* スタッキングコンテキストを生成させる */
position: absolute;
}
.special-components__item {
position: absolute;
z-index: 100;
}
.modal {
position: absolute;
z-index: var(--layer-stack-4);
}
基本的にz-index
の指定だけで問題がない状態での HTML 構造が好ましいが、z-index: calc(var(--layer-stack-2) + 1);
のような指定をした場合に他のコンポーネントとの重なりが意図しない状態になる可能性が高い。子要素にz-index
の指定があるコンポーネントのルートにはisolation
の指定をしておくのが好ましい。
ちなみに、isolation
登場以前はスタッキングコンテキストの生成のためにtransform
を副作用のない指定をして生成するハックが存在していた(例:transform: scale(1)
)。
まとめ
-
z-index
はLayer Stack のルールに従って指定する - コンポーネントのルートには
isolation: isolate
を指定する
Discussion