UIライブラリに学ぶz-indexの設計

# 背景

z-indexをどのように設定していますか？
はじめのうちは、一般コンテンツよりヘッダーが前で、オーバーレイはさらにその前で、モーダルはもっと前で。。。と、ざっくりと相対的に決めてしまえば問題なく実装できると思います。

しかし、アプリケーションが大きくなってきたり、新しい開発者がどんどん入ってきたりすると、オレオレだと辛くなってきます。
私も無根拠に `z-index: 99999;` などと書いてしまっていましたが、「何かルールを設けては」と指摘されてしまいました。

デファクトになっているようなガイドラインはないっぽいので、
有名UIライブラリやOSSはどう設計しているのか、参考にするために調べてみました。

# CSSフレームワーク/UIライブラリ

## Bootstrap

言わずとしれたBootstrapは次のように設計されています。

```scss
$zindex-dropdown:          1000 !default;
$zindex-sticky:            1020 !default;
$zindex-fixed:             1030 !default;
$zindex-modal-backdrop:    1040 !default;
$zindex-modal:             1050 !default;
$zindex-popover:           1060 !default;
$zindex-tooltip:           1070 !default;
```

上記にないコンテンツは0~999でということでしょう。
次いでドロップダウンメニュー、スティッキーヘッダーと続いています。

(ソース) https://getbootstrap.jp/docs/4.2/layout/overview/#z-index

## Semantic UI

Semantic UIも人気のCSSフレームワークです。

Semantic UIはドキュメント等にz-indexの指標はまとまっていませんでしたが、
https://github.com/Semantic-Org/Semantic-UI/search?q=zIndex&unscoped_q=zIndex
を見る限り、ざっくり以下のような感じかと思います。

```
メインコンテンツ: ~200くらい
ヘッダー: 800
プログレスバー: 999
オーバーレイ: 1000
モーダル: 1001
ポップアップ: 1900
```

Bootstrapほどちゃんと決まってない感じもしますが、数字のオーダー的にはBootstrapと似たような感じです。

## Material-UI

人気のReactベースなUIコンポーネントライブラリです。

```
mobile stepper: 1000
speed dial: 1050
app bar: 1100
drawer: 1200
modal: 1300
snackbar: 1400
tooltip: 1500
```

Bootstrapと似た設計です。
0~999は一般のコンテンツなのでしょう。
モーダルを表示したときのオーバーレイなどは、drawerとmodalの間の1201~1299のどこかであることが推測できます。

(ソース) https://material-ui.com/customization/z-index/

## UIライブラリまとめ

なんとなくUIライブラリではどのようにz-indexが設計されているのかがわかりました。

1000未満程度はテキストフィールドやボタンなど、一般的なコンテンツが占めるようにしていて、
1000以上でフローティング要素などを、その役割順に設定していっています。
Semantic UIのように、1しかz-indexの値を足さない事もあれば、10~100程度足して余裕をもたせることもあるようです。

# OSS(Web)

次に、有名なOSSではどんな感じでz-indexを設定しているのか見てみます。

## GitLab

GitLabはOSSでコードを公開しています。
ざっくり以下のような感じです。

```
popover: 240
dropdown: 300
notification-message: 999
performance-bar: notification-message + 1
footer-message: 1000
header: 1000
overlay: 1031
```

popoverが結構低層で、dropdownメニューとかぶったとき下に行ってしまいますが、あまり起こり得ないので問題ないのでしょう。
performance-bar(進捗バー的なもの?)は、scssの定数で、notification-messageよりひとつ上に表示するようになっています。
このように、ある程度のルールだけ定数で持っておいて、細かい部分は`+1`するといった運用は実践的に思えます。

(ソース) https://github.com/gitlabhq/gitlabhq/search?q=z-index&unscoped_q=z-index

## Mattermost(Web版)

MattermostはSlackライクなチャットツールです。
OSSなのでオンプレで運用できます。
Slackがセキュリティ上だめだから、Mattermostを自前のサーバに立てて使ったりしてる会社もあります。

```
dropdown: 100
popover: 999
overlay: 1000
modal: 1030
その他フローティング要素(emoji pickerなどいろいろ): 1050あたりでちょこちょこ
その他最上位要素(通知などいろいろ): 9999
```

だいたいこんな感じでした。
こちらはGitLabと比べて、あまりしっかりとルールがあるようには思えませんでした。
9999が最上位ということは決まってるっぽいですが、9999の要素がいくつもあります。

(ソース) https://github.com/mattermost/mattermost-webapp/search?q=z-index&unscoped_q=z-index

# 調査を踏まえて

今回調べたことを踏まえて、開発中のWebサービスのz-index設計は以下のようにしてみました。

```
~ 0             : 背景要素
~ 1000          : 主なコンテンツ
1001 ~ 1099     : フローティング要素
1100            : ヘッダー
1150            : Overlay(ドロワー背面)
1200            : ドロワー、サイドバー
1250            : Overlay(ドロワー前面)
1300            : モーダル
1400            : Snackbar(通知ポップアップ)
1500            : Tooltip(要素の説明ポップアップ)
```

上記すべて使うかはわかりませんが、プロジェクトが大きくなる前に指標を決めておくのは有効そうです。
実際の運用では、`theme.ts`などと、テーマ用のファイルを作って、そこですべて定義してテーミングします。

これがだけが絶対的な値となり、これ以外にz-indexを設定する必要がある場合は、以下のように相対的に設定することで、cssのマジックナンバーをなくします。

```
z-index: ${theme.zIndex.overlay + 1};
```

何かUIライブラリを入れている場合は、そのライブラリのz-indexの設計を調べて、それを踏襲すると良いかと思います。
(自前ルールにライブラリの方を合わせるためにオーバーライドする手間がかかるため)

このように設計することで、統一感があり堅牢なcssになるかと思います。