👨‍👩‍👦‍👦

z-indexの管理方法

2022/10/19に公開


画像はNovelAIでstacking contextと入れた時の出力

理想を言うとz-indexを使う必要は無い

理想を言えば、ModalやDialogなどのfloating contentsはDOM構造の下部にposition: fixedposition: absoluteで適切に配置すれば必然的に全てのコンテンツの一番上に被さる形になる。floading contents同士の重なり順も後に書いてあるものが上になるため、「適切なマークアップならz-indexは必要ない」という理想を掲げることはできます。

でもそんな理想的なDOM構造なんてないわけで。

基本はコンポーネント内で重ね合わせコンテキスト(Stacking context)を独立させる

稀に実装ではDOM構造でデザインと機能を両立するためにz-indexを駆使しますが、その場合でも基点となるコンポーネントにposition: relativeを指定するなどしてStacking contextを独立させることで重なり順の整理を図ります。

それぞれが独立しているという保証があれば、z-indexも1~5程度までを使えば大抵の実装は大丈夫でしょう。
z-indexによる重なり順整理が発生する1つのStacking contextは1コンポーネント(1ファイル)に収めることを気を付ければ事故が起こることも減ります。

更に言えば、単コンポーネント内で収まるなら変数で管理するほどではないとも言えますが、この辺の塩梅はチームの好みの方法で良いと思います。

floating contentsはcss variablesで整理する

必ずコンテンツ全体の上部に「浮いている」コンテンツはz-indexをその場で決めるのではなく、変数でルールを決めてしまう方が安全でしょう。

自分でDOM構造を把握してコントロールできる場合は必要性が薄くなりますが、reactのPortalを利用したり動的にDOM構造が変化する場合はz-indexに任せるのが安全です。

以下は変数一覧の一例

:root {
  --mer-z-index-popup-menu: 1000;
  --mer-z-index-navigation-top: 1100;
  --mer-z-index-information-popup: 1200;
  --mer-z-index-modal: 1300;
  --mer-z-index-dialog: 1300;
  --mer-z-index-snackbar: 1400;
}

1000から始まっているのは単純な重なりの整理じゃなく浮いてるんだぞという気持ちを表しています。
100からでも良いと思いますが、その場合でも100刻みが良いかもしれません。
10からは...ちょっと少ないかも。後述する追加のコンポーネントのためにあと一桁増やしたいところです。

それぞれの数字が100づつ空いているのは、歴史の重なりによって新たなコンポーネントが追加された時のための余剰分です。10001100の間に何か挟みたかったら1050となります。追加の際に全部ずらせば良いと言えばそうなのですが、一時的なコンポーネントでも簡単に追加するための措置です。(または、一つのプロジェクトを複数のチームが参照する場合にも耐えられる)

また上記の例だと、例えばmodaldialogは絶対同じタイミングでは出さないぞという意思が見て取れます。
このデザイン上のルールはプロダクトごとに変わってくるので、相談してちゃんとルールを作るのが一番大事です。

上から順番に心掛ける

ここからは個人の好みが多分に入りますが、基本上から順番に心掛けることでz-indexの乱用は減るでしょう。多分。何事もまずはz-indexを使わなくても良い方法を考え、デザイン的に無理かまたはマークアップ上(アクセシビリティ上)DOM構造が決まっている場合はz-indexの出番です。
また、コンテンツ全体の上に浮いていることが確定しているコンポーネントは、デザイン時点で順番について確定させましょう。そうすれば自ずとModalとDialogの同一画面における扱いなど、画面のルールも決まってきます。

Discussion