いつから、z-indexがpositionだけのものだと錯覚していた？

タイトルの元ネタになっている『BLEACH』は読んだことありません。

# 悩ましいz-index問題

CSSを学んだことある人なら一度は通る`z-index`問題。単純に`z-index`の値で重なりが決まるのではなく、親要素との関係によって重なりが変わるので複雑です。つい`z-index: 9999`はやってしまいます。（一番上なんだな、っていうのが分かりやすいので良いとは思いますが）

これが問題になるのは`position`のプロパティを使ったときが多いですが、`position`以外にもz-indexが有効になるプロパティがあります。

具体例がこちら↓
<p class="codepen" data-height="430" data-theme-id="default" data-default-tab="css,result" data-user="Nishihara" data-slug-hash="jOEdywV" style="height: 430px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="z-index">
  <span>See the Pen <a href="https://codepen.io/Nishihara/pen/jOEdywV">
  z-index</a> by Nishihara (<a href="https://codepen.io/Nishihara">@Nishihara</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

この記事ではHTMLは以下のように`id`の小さい方から書かれている前提になります。

```html
<section class="section section1">
  <div id="block1">z-index: 3</div>
  <div id="block2">z-index: 2</div>
  <div id="block3">z-index: 1</div>
</section>
```

# display: flexの時

`display: flex`を使った際の子要素も実は`z-index`が有効になります。flexだけを使って重ねるというのは、あまりない場面かもしれませんが、ネガティブマージンを使って重ねると`z-index`が効いているのが分かります。

```css
.section1 {
  display: flex;
  justify-content: flex-start;
}

#block1 {
  background-color: rgb(228, 100, 100);
  z-index: 3;
}

#block2 {
  background-color: rgb(100, 228, 100);
  z-index: 2;
  margin-top: 40px;
  margin-left: -80px;
}

#block3 {
  background-color: rgb(100, 100, 228);
  z-index: 1;
  margin-top: 80px;
  margin-left: -80px;
}
```

# display: gridも

flexと同様に`display: grid`でも`z-index`が使えます。そもそも`grid`でレイアウトを重ねることは少ないと思いますが。。。

```css
.section2 {
  display: grid;
  justify-content: flex-start;
  grid-template:
    "block1 block2 block3" 120px /
    120px 120px 120px;
}

#block4 {
  background-color: rgb(228, 100, 100);
  z-index: 3;
}

#block5 {
  background-color: rgb(100, 228, 100);
  z-index: 2;
  margin-top: 40px;
  margin-left: -80px;
}

#block6 {
  background-color: rgb(100, 100, 228);
  z-index: 1;
  margin-top: 80px;
  margin-left: -160px;
}
```

# 組み合わせても有効になる

これらも要素に`z-index`が有効であることを知らなくても、それぞれを単体で使う場合にはそんなに問題はありません。問題になってくるのは、`position`やこれらを組み合わせた時です。

例えば下記のように、flexで並べて、子要素に`position: absolute`を使って配置し、`transform: translate`で重ねた場合はどうでしょう？その場合も`z-index`の値が効いてきます。

```css
.section3 {
  display: flex;
  position: relative;
  justify-content: flex-start;
}

#block7 {
  background-color: rgb(228, 100, 100);
  z-index: 3;
}

#block8 {
  background-color: rgb(100, 228, 100);
  z-index: 2;
  position: absolute;
  top: 40px;
  left: 40px;
}

#block9 {
  background-color: rgb(100, 100, 228);
  z-index: 1;
  transform: translate(-40px, 80px);
}

```

この場合は、`#block7`が一番上にきます。

# z-indexパズル

`z-index`を指定しない場合は重ね合わせコンテキストのルールに従って、HTMLで後に書かれているものが上になります。では、次のような場合どうでしょう。

```css
.section4 {
  display: flex;
  position: relative;
  justify-content: flex-start;
}

#block10 {
  background-color: rgb(228, 100, 100);
}

#block11 {
  background-color: rgb(100, 228, 100);
  position: relative;
  margin-top: 40px;
  margin-left: -80px;
}

#block12 {
  background-color: rgb(100, 100, 228);
  margin-top: 80px;
  margin-left: -80px;
}
```
子要素には`z-index`が指定されていません。なのでHTMLで一番最後の要素の`#block12`が一番上に来そうですが、**実はそうではありません**。

よく見ると、`#block11`には`position: relative`が指定されています。そうすると、新たに重ね合わせコンテキストが発生するので`#block11`が一番上にきます。しかしここに、

```css
#block10 {
  background-color: rgb(228, 100, 100);
  z-index: 1;
}
```
と`z-index`を指定すると通常の重ね合わせコンテキストを上書きするように`#block10`が一番上に来ます。ここまでくるとz-indexパズルですね！


# 最後に
重ね合わせがうまく行かなかったら、これら`z-index`が有効なプロパティも疑ってみてください。より詳しいスタッキングコンテキストとz-indexの関係は[『君は真に理解しているか？z-indexとスタッキングコンテキストの関係』](https://ics.media/entry/200609/)もご参照ください。