前提
今回の回答では、以下のコードを用います。これは今回生じている問題に関係のない部分を省いたコードです。このコードでは、 .z-index20
クラスを div.col-12
要素の祖先へ適用すると、ボタンのホバー時のアニメーションが正常に動作しないようになっています (動作確認用リンク)。
HTML
1<div class="container bg-dark">
2 <div class="row">
3 <div class="col-12 z-index20">
4 <button type="button" class="btn">ABOUT</button>
5 </div>
6 </div>
7</div>
CSS
1*,
2::after,
3::before {
4 box-sizing: border-box;
5}
6
7button,
8html [type="button"] {
9 -webkit-appearance: button;
10}
11
12body {
13 margin: 0;
14}
15
16.bg-dark {
17 background-color: #343a40;
18}
19
20.container {
21 width: 100%;
22 padding: 0 15px;
23 margin: 0 auto;
24}
25
26.row {
27 display: flex;
28 flex-wrap: wrap;
29 margin: 0 -15px;
30}
31
32.col-12 {
33 flex: 0 0 100%;
34 max-width: 100%;
35}
36
37.btn {
38 border: 3px solid #3498db;
39 background: none;
40 border-radius: 10px;
41 padding: 10px 20px;
42 font-size: 30px;
43 font-family: "montserrat";
44 cursor: pointer;
45 position: relative;
46 overflow: hidden;
47 color: #3498db;
48}
49
50.btn:hover {
51 color: #fff;
52}
53
54.btn::before {
55 content: "";
56 position: absolute;
57 top: 0;
58 left: 0;
59 width: 100%;
60 background: #3498db;
61 z-index: -1;
62}
63
64.btn:hover::before {
65 height: 200%;
66}
67
68.z-index20 {
69 z-index: 20;
70}
回答
colに指定されているposition:relative;とz:index:20の組み合わせると、
子要素でのz-index:-1は効かないと理解しています。
それなれなのにz-index:-1が必要な理由がよくわかりません。
いいえ、「子要素での z-index
プロパティ」は祖先要素で生成されたスタックコンテキストにおいて効果があります。z-index: -1
は祖先要素におけるスタックコンテキストでの描画順序を変更しています。
また、cus-index20はcolのところに書かないとならず、rowやcontainerのところに書くとうまく動きが出ないこともわかりません。
この挙動は、 z-index
プロパティやスタックコンテキストの効果について理解しておくと理解がしやすくなります。以下でこれら二つについて説明します。
z-index
プロパティとは
z-index
プロパティに整数値を指定することで、スタックコンテキストにおける要素の描画順序 (重なる順序) を指定することが出来ます。また、 z-index
プロパティに整数値を指定すると、その要素がスタックコンテキストを確立します。ここで、 z-index
プロパティは位置指定された要素を適用対象の要素としています。そのため、 position
プロパティの値が static
の要素では z-index
プロパティの値は auto
となります。
スタックコンテキストとは
スタックコンテキストは、 z-index
プロパティによる描画順序の影響が及ぶ範囲を示した概念です。スタックコンテキスト内での z-index
プロパティの描画順序は、その他のスタックコンテキストに影響を及ぼしません。スタックコンテキストは主に、特定の CSS プロパティが指定されている場合に生成されますが、ルート要素は常にスタックコンテキストを生成します。
Each box belongs to one stacking context. Each positioned box in a given stacking context has an integer stack level, which is its position on the z-axis relative other stack levels within the same stacking context. Boxes with greater stack levels are always formatted in front of boxes with lower stack levels. Boxes may have negative stack levels. Boxes with the same stack level in a stacking context are stacked back-to-front according to document tree order.
The root element forms the root stacking context. Other stacking contexts are generated by any positioned element (including relatively positioned elements) having a computed value of 'z-index' other than 'auto'. Stacking contexts are not necessarily related to containing blocks. In future levels of CSS, other properties may introduce stacking contexts, for example 'opacity' [CSS3COLOR].
ここで、今回問題となっている挙動を理解するにあたって必要となるスタックコンテキストの生成条件を挙げておきます。
- ルート要素は常にスタックコンテキストを生成する。
z-index
プロパティの値が auto
以外の位置指定要素はスタックコンテキストを生成する。
z-index
プロパティの値が auto
以外のとき、 flex アイテムはスタックコンテキストを生成する。
Flex items paint exactly the same as inline blocks [CSS21], except that order-modified document order is used in place of raw document order, and z-index values other than auto create a stacking context even if position is static (behaving exactly as if position were relative).
以上を踏まえたうえで、改めて回答文の冒頭に載せたコードをみます (動作確認用リンク)。 div.col-12
要素に .z-index20
クラスが指定されているとき、生成されているスタックコンテキストは、
- ルート要素
div.col-12
要素
button.btn::before
擬似要素
の三つです。そして、 button.btn::before
擬似要素は、 div.col-12
要素のスタックコンテキストに所属しており、 z-index
プロパティの値は -1 であるため、 div.container.bg-dark
要素よりも上で、 button.btn
要素よりも下の位置に配置されます。
次に、 div.col-12
要素の祖先要素 (今回は .row
要素とする) へ .z-index20
クラスが指定されたときを考えてみます (動作確認用リンク)。このとき生成されているスタックコンテキストは、
- ルート要素
button.btn::before
擬似要素
の二つになります。すると、 button.btn::before
擬似要素はルート要素のスタックコンテキストに所属します。これにより、 button.btn::before
擬似要素はルート要素より上で、 div.container.bg-dark
要素や body
要素よりも下の位置に配置されます。そうすると、 button.btn::before
擬似要素は隠れ、ホバー時に button
要素の文字色のみが変化しているように見えます。これが .cus-index20
クラスを移動させたときの挙動の変化の原因です。この動作は、適切な位置でスタックコンテキストを生成することで解決することが出来ます (動作例)。