CSSでz-indexが効かない時の4つの原因とその対応方法
Post on:2021年5月16日
CSSでレイアウトする際、z-indexが期待通りに機能しない時がありませんか?
z-indexは重なり順を定義するプロパティですが、単なる重なり順だけでなく、いくつか複雑なルールがあります。
z-indexがうまく効かない時の主な4つの原因とそれぞれへの対応方法について紹介します。
4 reasons your z-index isn’t working (and how to fix it)
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
- はじめに
- 1. 同じコンテンツ内で積み重なっている要素は出現順に表示され、後の要素は前の要素の上に表示される
- 2. 要素にpositionが設定されていない
- 3. opacityやtransformなどのプロパティを設定すると、要素は新しい積み重ねコンテキストに配置される
- 4. 子要素のz-indexレベルを制限する親要素
- 4の解決方法
- 4の代替の解決方法
- まとめ
はじめに
z-indexとは、レイヤー上に要素を重ねて配置できるCSSのプロパティです。このプロパティはとても便利で、レイアウトする際にも重要なプロパティです。
しかし残念ながら、z-indexは直感的な方法で機能するとは限らないプロパティの1つです。一見簡単そうに見えるかもしれません。例えば、より高いz-indexの要素はより低いz-indexの要素の上に配置されることを意味します。しかし、いくつかの複雑なルールがあります。そして、z-indexを999999に定義することでいつも問題を解決することはできません。
この記事では、z-indexがうまくいかない一般的な4つの理由と、それを修正する方法について詳しく説明します。
実際のコードを見て、その問題を解決します。この記事を読んだ後は、z-indexによるこれらの問題を理解して回避することができるでしょう。
1. 同じコンテンツ内で積み重なっている要素は出現順に表示され、後の要素は前の要素の上に表示される
最初の例は、3つの要素を含むシンプルなレイアウトです。
- ネコの画像
- テキストのブロック
- 同じネコの画像をもう一つ
HTMLのマークアップは下記の通りです。
1 2 3 4 5 6 7 |
<div class="cat-top"></div> <div class="content__block"> テキスト </div> <div class="cat-bottom"></div> |
このレイアウトでは、テキストブロックにネコ画像を重ねることが理想的です。
レイアウトを達成するために、上下のネコ画像にCSSでマイナスのマージンを加えて、テキストブロックと少し重なるようにしました。
1 2 3 4 5 6 7 8 |
.cat-top { margin-bottom: -110px; } .cat-bottom { float: right; margin-top: -120px; } |
この実装で下記のようになります。
See the Pen
Z-index: #1: set position, #2: natural stacking order, #3: CSS properties by Jessica (@thecodercoder)
on CodePen.
上のネコ画像は期待通り、テキストブロックの下に配置されています。しかし、下のネコ画像は上に配置されています。これは期待通りではありません。
なぜこのようなことが起きているのでしょうか?
理由は、Webページ上の自然な重なり順によるものです。このルールは、基本的にどの要素が一番上に、どの要素が一番下になるかを決定します。要素にz-indexが定義されていなくても、要素が最上位になる理由はあるということです。
このデモでは、どの要素にもz-indexは定義されていません。そのため、これらの重なり順は、HTML上での出現順序によって決定されます。つまり、マークアップで後に記述されている要素は、その前にある要素の上に配置されます。
参考: The stacking context
上記のデモはこのルールに従って配置されています。このことが、最初の猫はブロックの下にあり、そしてブロックは2番目の猫の下にある理由です。
記述順による積み重ねの順序は理解できました。それを理解した上で、2番目の猫をブロックの下にするにはどのようにCSSを修正するとよいでしょうか?
2. 要素にpositionが設定されていない
積み重ねの順序を決定する他の要因は、要素にpositionが設定されているかどうかです。要素の位置を設定するには、CSSのpositionプロパティをstatic以外(relativeやabsoluteなど)を定義します。
参考: How to use CSS position
このルールを使用すると、配置された要素は配置されていない要素の上に表示されます。さきほどのテキストブロックに「position: relative;」を加え、ネコ画像はそのままposition無しにすると、テキストブロックはネコ画像の上に配置されます。さきほどのデモに「position: relative;」を加えると、下記のように表示されます。
テキストブロックに「position: relative;」を追加
次にやるべきことは、transformプロパティを使って下のネコ画像を逆に回転させることです。2匹のネコは頭だけが出て、テキストブロックの表示されるでしょう。
しかしそれを実現すると、z-indexに関連した混乱が起きる可能性があります。次に、この問題とその解決方法について説明します。
3. opacityやtransformなどのプロパティを設定すると、要素は新しい積み重ねコンテキストに配置される
さきほど述べたように、下のネコ画像を逆に回転させたいと思います。回転させるには、「transform: rotate(180deg);」を加えます。
1 2 3 4 5 |
.cat-bottom { float: right; margin-top: -120px; transform: rotate(180deg); } |
しかし、このCSSでは下のネコ画像が再びブロックの上に表示されてしまいます。
transformを加えると、下のネコ画像はブロックの上に
何が起きているか説明します。
この問題に頻繁に遭遇することはないかもしれませんが、積み重ねの順序はtransformやopacityのようなプロパティを要素に定義すると、自身の新しい積み重ねコンテキストに配置されます。
これが意味するのは、.cat-bottom要素にtransformを加えると、z-indexが0であるかのように振る舞うということです。ご覧の通り、positionやz-indexは定義されていません。W3.orgに、opacityプロパティとどのように連動するかについての有益なドキュメントがあります。
参考: Transparency: the ‘opacity’ property
さきほどはテキストブロックにz-indexを加えず、position:relative;のみを追加しました。positionを定義していないネコ画像の上にブロックを配置にするにはこれで十分でした。
しかし、.bottom-cat要素は、z-index:0;で相対的に配置されているかのように振る舞っているため、transformを加えた結果、ブロックの上に表示されます。
これを解決するには、「position: relative;」を加え、さらにz-indexを明示的に定義します。安全策として、ネコ画像に相対的に低い値でz-indexを定義します。
1 2 3 4 5 6 7 8 |
.content__block { position: relative; z-index: 2; } .cat-top, .cat-bottom { position: relative; z-index: 1; } |
こうすることで、基本的なz-indexの問題はすべてではないにしても、ほとんどが解決されます。
それでは、z-indexが機能しないという最後の理由に進みましょう。少し複雑です、なぜなら親子要素が関係するからです。
4. 子要素のz-indexレベルを制限する親要素
まずは、デモを見てみてください。
See the Pen
Z-index: #4 different stacking contexts by Jessica (@thecodercoder)
on CodePen.
このデモは画像とテキストが配置されたシンプルなページで、コンテンツの上に「Send Feedback」と書かれたピンクのサイドタブがあります。そして、ネコ写真をクリックすると、グレーの背景のオーバーレイでモーダルウィンドウが表示されます。ただし、モーダルウィンドウが表示されていても、サイドタブはグレーのオーバーレイの上に表示されています。
各要素のポイントとなるCSSを見てみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
.content { position: relative; z-index: 1; } .modal { position: fixed; z-index: 100; } .side-tab { position: fixed; z-index: 5; } |
すべての要素にpositionが定義されており、サイドタブのz-indexは5で.content要素の上に配置されています。z-indexは1です。.modal要素のz-indexは100で、z-index: 5;のサイドタブの上に配置されています。
モーダルウインドウが一番上なのに、サイドタブが一番上に表示されてしまいます。なぜこのようなことが起きているのでしょうか。
前述で要素にpositionが定義されているかどうか、マークアップでの記述順はどうかなど、積み重ねコンテキストに関連するいくつかの要因について説明しました。
しかし、積み重ねコンテキストにはもう一つルールがあり、子要素はその親の積み重ねコンテキストに限定されます。
問題の3つの要素を詳しく見てみましょう。
これがマークアップです。
1 2 3 4 5 |
<section class="content"> <div class="modal"></div> </section> <div class="side-tab"></div> |
マークアップを見ると、コンテンツとサイドタブの要素が兄弟であることが分かります。つまり、これらはマークアップで同じレベルに存在します(z-indexレベルとは異なります)。モーダルは、.content要素の子要素です。
モーダルは.content要素の子であるため、そのz-index: 100;は親の.content要素の内部にのみ効果があります。例えば、他の子要素がモーダルの兄弟である場合、それらのz-index値はそれらを互いの上または下に配置されます。
しかし、親の.content要素のz-indexが1で定義されているため、その子要素のz-index値は親の外側にあるものを意味するものではありません。そのため、その子要素(モーダル)は、そのz-indexレベルから抜け出すことはできません。
このルールは隠喩を使って覚えておくことができます。子供はその親によって制限されることがあるけれど、解放されることはありません。
この問題を解決する方法はいくつかあります。
4の解決方法
解決方法はモーダルをコンテンツの親の外側に移動し、メインの積み重ねコンテキストに移動します。修正されたマークアップは下記のようになります。
1 2 3 4 5 |
<section class="content"></section> <div class="modal"></div> <div class="side-tab"></div> |
モーダルは他の2つの兄弟要素です。これで、3つの要素すべてが同じ積み重ねコンテキストに配置されるため、それぞれのz-indexレベルは互いに影響を及ぼします。
修正した積み重ねコンテキストでは、要素は上から下に向かって次の順序で表示されます。
- modal (z-index: 100;)
- side tab (z-index: 5;)
- content (z-index: 1;)
4の代替の解決方法
別の解決方法としては、コンテンツからpositionを削除して、モーダルのz-indexを制限しないようにすることです。
マークアップを変更したくない場合・できない場合は、.content要素からpositionを削除することでこの問題を解決できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.content { // positonを削除 } .modal { position: absolute; z-index: 100; } .side-tab { position: absolute; z-index: 5; } |
.content要素のpositionが削除されると、モーダルのz-index値は制限されなくなり、モーダルはz-index: 100;でサイドタブの上に配置されます。
この方法はうまくいきますが、私は個人的には最初の解決方法を勧めます。
なぜなら、将来的に何らかの理由で.content要素にpositionを定義しなければならない場合、再び同じ問題が起きてしまうからです。
まとめ
このチュートリアルはあなたの役に立ちましたか?
まとめると、z-indexに関する問題のほとんどは、次の2つのガイドラインに従って解決できます。
- 要素にpositionが定義されているか、z-indexの番号が正しい順序であるか、を確認する。
- 子要素のz-indexレベルを制限する親要素がないことを確認する。
リソース
sponsors