CSS)z-indexのベストプラクティスを考える
CSSのz-index
プロパティについてツイートしたところ、色んな人から参考意見をいただきました。
要素の重ね順の制御をその場しのぎで乗り切っているWebサイト、実はけっこう多いような気がします。今回はz-index
のベストプラクティスを自分なりに探ってみたいと思います。
z-index
に詳しいゼットインデクサーのみなさま、意見やアドバイスがあれば是非コメントを残していってください。
z-indexについて考えるときの前提
まず、ざっくりと考え方をまとめておきます。ウェブページの要素の重ね順を理解するには「スタッキングコンテキスト(重ね合わせコンテキスト)」を知っておく必要があります。
詳しくはz-indexとスタッキングコンテキストの関係 - ics.mediaがとても分かりやすいのですが、ここではざっくりとした説明だけ載せておきます。
z-indexは数字が大きい方が上にいくとは限らない
↑ 例えば、z-index:3
の要素と、z-index:99
の要素があるとします。どちらもが同じ親要素のすぐ下にいるような場合は、z-index:99
が上にきます。これなら直感的で分かりやすいですね。
↑ しかし、どちらかが属する親要素にz-index
が指定されている場合は話が変わってきます。z-index:99
がz-index:1
の要素内に入っている場合、たとえ99
であってもz-index:3
より下になります。
↑ なぜならz-index:3
の要素とz-index:99
は別のスタッキングコンテキストに属しているからです。z-index:99
は、親要素がつくったスタッキングコンテキストの中では最強かもしれませんが、しょせんそのコンテキスト内での強さになってしまうわけです。
z-index
だけではない
スタッキングコンテキストを作るのはより話をややこしくするのが「スタッキングコンテキストを作るのがz-index
だけではない」ということです。たとえばopacity
プロパティや、transform
プロパティを使ったときなんかにもスタッキングコンテキストが作られます。position: fixed
を使うとz-index
を使わなくても、スタッキングコンテキストが作られます。
他にも色々あるのですが、詳しくはMDNの重ね合わせコンテキストにまとまっています。
z-indexの値が同じ場合は、後ろに配置された要素が上にくる
z-index
の値が同じ場合、後ろに配置された要素が上に重なります。
↑ この2つの要素にはz-index
を指定していないため、どちらもz-index:0
となっています。そのため、後ろに配置された要素が、重なり順では上になります。
つまり、前後の要素どうしを重ねたいような場合にz-index
を使う必要はありません。
z-indexのベストプラクティス
ここからが本題です。現時点での個人的な意見であるため、後から修正する可能性ありです。
1. 重ね順はできる限り、コンテキスト内でのみ制御する
スタッキングコンテキストが作られるケースを全て把握し、管理するのは困難です。そのため、そもそも離れた場所にいる要素どうしの並び順の制御はできる限りしないようにするのが良いと思います。
<section>
<div>😺</div>
</section>
...
<section>
<div>
<p>🦁</p>
</div>
</section>
↑ 離れた場所にいる要素どうしの重ね順をz-index
でコントロールするのは困難です。
たとえば、離れた場所にいるネコ要素😺をライオン要素🦁より上に重ねたい…みたいなことをやるとカオスになります。スタッキングコンテキストがバラバラで、z-index
の値の大きさだけでコントロールできなくなってしまう可能性があるからです。
そのうえ、後からヒョウ🐆が登場し、「ヒョウ🐆は、ネコ😺より上で、ライオン🦁よりは下で……」みたいなことになりがちだからです。
(分かりづらい例えですね)
コンポーネント内で重ね順をコントロールする
基本的には、ひとつのコンポーネントの中で重ね順のコントロールを完結するべきです。[コンポーネントAの中のある要素]と、[コンポーネントBの中のある要素]の重ね順をコントロールするべきではありません。
z-index
を使う必要はない
小さいコンポーネントであればさきほど書きましたが、z-index
の値が同じ場合は、後ろに配置された要素が上にきます。そのため、上に重ねたい要素を後ろに配置すれば、z-index
を使う必要はありません。
↑ 例えば、画像の上にテキストを重ねるようなコンポーネントの場合、画像よりもテキストの要素を後ろに位置すれば良いだけです。
z-index:1
だけを使う
使うとしても大きなコンポーネントになってしまった場合もz-index:1
さえ使えれば、コンポーネント内での重ね順の制御は十分できると思います。それ以上に値のバリエーションが必要となる場合、コンポーネント自体の設計を見直すべきでしょう。
2. コンポーネントをまたぐ場合には変数を使う
実際にWebサイトを作っていくと、複数のコンポーネントをまたいで重ね順をコントロールする必要が出てくることもあります。よくあるのが「上部に固定されたヘッダー」、「下部に固定されたヘッダー」、「モーダル」といった組み合わせです。
↑ こちらはWeb版のTwitterのスクショです。固定ヘッダーは、コンテンツ部分より上でなければならないが、モーダルよりは下でなければならないという状態ですね。
モーダルは「半透明のバックドロップの部分」と「本体部分」に分かれますが、この2つは同じコンポーネント内で制御すればOKだと思います。つまり、ひとつのスタッキングコンテキストに閉じ込めてしまい、常にバックドロップよりモーダル本体が上に来るようにします。
ややこしいのはヘッダーコンポーネントと、モーダルコンポーネントの重ね順のコントロールです。常にこの2つのコンポーネントが並ぶときに、モーダルが後ろに配置されるようにすればそれだけで事足りますが、z-index
で「モーダル > ヘッダー」と決めておきたい場合もあると思います。
z-index
の値を決めておく
変数で役割ごとのそのような場合は、役割ごとのz-index
の値を変数に入れてしまって、数字を直接書かないようにするのが良いと思います。
(こちらのツイートを参考にさせていただきました)
たとえばCSS変数を使う場合、以下のようにします。
:root {
--z-index-header: 100;
--z-index-modal: 200;
}
あとはヘッダーとモーダルそれぞれのコンポーネント内のルートとなる要素にこの変数をあてておきます。
.modal {
position: relative;
z-index: var(--z-index-modal);
}
.header {
position: relative;
z-index: var(--z-index-header);
}
このようにすれば、コンポーネントを使うときに重ね順について意識する必要が無くなります。また、プロジェクト内に複数のモーダルコンポーネントが存在するような場合にも同じ変数を使い回すことができます。
z-index
の値を決めておく
使って良い複数人が触るプロジェクトの場合「z-index
の値としては1
もしくは 変数 以外使ってはいけない」というような規約をあらかじめ決めておくのが良いと思います。このルールを徹底しないと、さまざまなz-index
の値と変数が入り乱れてよりカオスになってしまう可能性があります。
変数を増やさない
また、z-index
用の変数は最小限に抑えるべきだと思います。z-index-modal
とz-index-modal-upper
が存在するようになってしまったらオワコンです。そうならないために「z-index
用の変数を増やすときは上長に申請書類を提出し、ハンコで承認を得たうえで厳密に保管する」などとルールを決めておくべきでしょう。
個人的z-indexのベストプラクティスまとめ
- できる限りコンポーネント内で重ね順をコントロールする
- コンポーネント内の要素の重ね順のコントロールには、
z-index:1
だけを使う もしくはz-index
を使わない - 複数のコンポーネントをまたぐ重ね順のコントロールにはCSSやScssの変数を使う
Discussion