【z-index:-1 の活用】z-index:-1 を BODY タグの子以外で使う方法
z-index:-1 を BODY タグの子以外で使う方法を調査・実験しました
z-index : -1 は何のために使うのか?
この記事は デザイナーさんやフロントエンドエンジニアさん向けに書いています。
そもそも、[z-index : -1] という指定は、ブラウザがCSS3に対応してくれたことで、[transform の rotateZ] 、 [box-shadow] 、 [疑似要素のbefore・after] を使って、div や section のボックスに、通常の影ではなく、微妙に立体的な影を付ける、というテクニックが紹介された時に広まった、裏技的に見える数値指定だと思います。
想像してみれば [z-index:正の整数値] だけで Z軸方向へのタグ要素の重なり順を指定できますので、わざわざ[-1]のような負の値を指定することはあまりないかと思われるからです。
※プログラマ的発想をする制作者の方は、昇順降順の発想で、下から配置するイメージを持っていて -100 -99 -98 … のような使い方をする人もいるかもしれません。
※全要素に z-index 指定するのが大変なので、指定していない auto な要素の下に、ソース上ではその要素よりも後に記述したものを、どうしてもZ軸方向で下に配置したい、という場合が無いとは言えないので、そんな時には [-1] を使うと楽ができる、そういう使い方もあるかもしれない、とも想像できますので、普通は使わない、などと自分視点だけで言い切ることはできないですね…。
一応、マイナスは前後表示優先低め、というものなので、一般にはあまり使われないと仮定します。
ですがなぜ、[z-index:-1]を使う、というアイデアが言われるようになったのか?
それは疑似要素(before , after)を、その親となるタグの下に表示したい時に使う、というTIPが流行ったからです。
『タグ要素とその疑似要素』の重なり順は、『bodyタグとその直接の子であるタグ要素』と同様です。
疑似要素の [before] は「要素の仮想的な最初の子要素」で、[afterは]「要素の仮想的な最後の子要素」というものだからです。
z-indexについて
原森でも、z-index 指定を初めて知った時には、特に使うこともなかったので、BODYからの絶対的なZ軸方向への指定順、などと勘違いしていました。
実際に原森サイトで使うことになったので、MDNで調べてみると、値を指定すると、『position が static 以外のもの』は『ローカルな重ね合わせコンテキストを新たに作る』という内容が書いてありました。
つまりはローカルな重ね合わせ順を持つレイヤーグループを作るようなもの、ということでした。
photoshop のレイヤーで例えれば、レイヤーにグループを作ると、そのローカルなグループ内だけの上下重ね合わせ順があり、グループ自体はその親のレイヤーにグループごと所属している、そういう感覚です。グループをドラッグして別のグループと上下位置を入れ替える時に、グループ内の z-index は関係なくて、グループ自体の z-index 値を変更している、という感覚です。
そして、グループに所属する要素に指定した z-index の値はグループ内だけの重なり順の指定なのです。
z-index:0を指定してあるタグ要素よりも z-index:-1 と書いたものが上に表示される場合や、
タグにz-index:0と書いて、その疑似要素を下に表示しようとしてz-index:-1と書いても上に出てしまう、感覚として理解しづらい、という意見を書いておられる web技術関連の記事を見かけることもありますが、それは原森も最初にそう勘違いしていた『z-index が絶対的なZ軸方向の並び順』と勘違いして [z-index] の仕様を認識してしまったからだと思われます。
下に普通にタグや疑似要素に-1を指定した例を表示しますが、普通に兄弟関係にあるタグに書けば、-1 は 0 より下に表示されます。
濁ったブルーの親 div に表示されているのは、兄弟 div が z-index 指定なしの状態の場合です。ソースの記述順に重なっています。
紫っぽい親 div に表示されているのは、兄弟 div に [z-index:0] [z-index:-1] [z-index:1] を指定した場合です。ちゃんと指定通りに重なっています。(逆に兄弟タグに普通に指定して、0より-1を上にすることの方が不可能かと思います)
黄色っぽい親 div に表示されているのは、div が1個だけで、[z-index:0]を指定し、疑似要素の before に[z-index:-1]、after に [z-index:1] を指定した場合です。疑似要素の-1は親の0より上に表示されています。
この現象を見て、-1 が 0 より上に表示されてしまう!W3Cはなぜこんな変な仕様にしているんだ、などと勘違いしてしまうのです。
備考:
※この記事中にちゃんと表示させるためのつじつまあわせとして、濁ったブルーの親 div には[z-index:1]、紫っぽい親 div には[z-index:2]、黄色っぽい親 div には[z-index:3]を指定しています。
意味的には違いますが、言葉的に某アニメの表現を使ってみれば、webページ1枚の中で指定してあるすべての [z-index] 値を見て、[-1]よりも下に表示されてしまう [z-index:0] はα世界線の値であり、その要素よりもなぜか上に表示される [z-index:-1] はβ世界線の値なのです。
つまりは世界線が違う値を見比べておかしい、理解できないと言ってしまっている、ということだと思います。
たびたび名前が出ますが、MDNさんにも、z-indexを指定すると『ローカルの重ね合わせコンテキストを作る』のでそこに所属する
『子孫要素の z-index は、この要素の外部にある要素の z-index とは比較されない』と書いてあります。
つまり、z-indexを指定すると『ローカルの重ね合わせコンテキストを作る』(β世界線が生まれる)のでそこ(β世界線)に所属する ことになってしまう『子孫要素の z-index は、この要素の外部(α世界線)にある要素の z-index とは比較されない』ということになります。
その説明の意味が理解できない時に、親を [z-index:0] にして、子を [z-index:-1] にしたけど、親より子が下に行かない、なので、0 より -1 が上に来るのには違和感がある…と思ってしまうという論なのですが、親に z-index を指定すると、その値である 0 は子には関係のない値となります。子から見れば、親は絶対的な枠となって、親の [z-index] と自分の値は比べることができなくなるのです。なぜなら親の [z-index:0] は親の親の絶対的な枠、つまりα世界線にある値だからです。
そして自分の [z-index:-1] は親が作ったβ世界線の値となるので、比較できなくなるのです。
勘違いの原因となるもう一つの値が [z-index:auto] です。
MDNの説明に書いてありますが、[auto] は 『ローカルな重ね合わせコンテキストを新たに作らない』ということです。
つまり、グループを作らず、親のレイヤーグループであるα世界線に所属しているタグ要素である、ということです。
z-index を指定しない場合は自動的に z-index:auto となります。
なので、autoは値指定ではなく、値を指定しない…つまり、auto状態の親の子は、重なり順に関しては、親と対等の世界線に所属して、親の影響に縛られず、親の親の枠で親と兄弟的な表示比較をされる、ということになります。
auto状態のタグの子要素は、表示位置的には直接の親のグループとしてひとかたまりにはならないのです。
なので、auto 状態の要素は z-index 値がないので、タグの表示仕様ルールや記述順、他のz-index値の優先順などの関係から上下表示位置が決まります。
疑似要素に z-index:-1 を指定してタグに影を演出できる理由
通常、z-indexを指定しないタグとその疑似要素は親であるタグが下にあり、疑似要素は親より手前に表示されますが、疑似要素だけに [z-index:-1] のような負の値を指定すると、auto状態の親よりも下に表示させることができます。
だからこそ、例えば BODY タグの直接の子であるタグの疑似要素( before や after)に [-1] を指定して、親より下に表示させる、という裏技的なテクニックで影をつける、というTIPとなっているのです。
webのブログなどで紹介される時、 [-1影] の TIP は、影を演出したサンプルと、その [-1] のソースだけを説明されている場合が多いかと思います。
なので、問題点として、他に親戚のおじさんやおじいさんのようなタグがいて、その人の影響で、before の影が彼らの下に表示されて見えなくなってしまう、という場合があったりして、どこでも使える技ではない、と思われてしまうのです。
※原森も汎用的ではない、などと仕様をよく調べずに思っていましたが、説明をよく読めば、解決策はあっけなく見つかってどこでも使えるようになりました。
タグと疑似要素の重なり順
z-index を指定したタグ要素のローカルなレイヤーグループが body タグのような感じでベースとなり、通常、疑似要素は親であるタグよりZ軸方向で手前、つまりは上に重なる状態となります。
親であるタグに[z-index:2]、beforeに[z-index:1]などの値指定をしたとしても、beforeは親であるタグより前に表示されてしまいます。
理由は、親であるタグに z-index値を指定してしまうと、そこからローカルなレイヤーグループが作られてしまうので、親のz-indexによる配置はα世界線になり、その値は親の親のグループ内での並び順のための値になるからです。
もちろんその時の [before] の z-index値はβ世界線の値となります。
『子孫要素(before)の z-index(z-index:1) は、この要素の外部にある要素(ローカルレイヤーを作った親タグ)の z-index(z-index:2) とは比較されない』(by MDN)
この場合、親は一番下にあるベースレイヤーとなり、疑似要素はその上にある子としての before や他の子の[z-index]の値や書き順タグ要素仕様順のルールで表示の優先度を判定されて表示されます。
よく考えれば、普通に指定すればいいのでは?
HTML5の基本としての、『タグは文書を構造化するためのものなので、余計な装飾用のタグを使わない。装飾は css で、ご利用は計画的に…』という思想を無視すれば、下記のように、単純に 装飾用としての div や span タグを使うだけで、[z-index:-1] を使わずに立体影をつけて装飾することは可能です。
divを二つ使って影演出
装飾用でdivタグを記述することを全然気にしないなら、これで [z-index:-1] がどこにでも使えずこまってしまう問題は解決です。
普通に [z-index] の数値で上下配置をしているだけになります。
HTMLソース
<div style="position:relative;top:0;left:0;width:180px;height:230px;background:rgba(200,200,200,1);">
<div class="bx_min">z-index:2</div>
<div class="bx_shd">z-index:1</div>
</div>
CSSソース
.bx_min{
position:absolute;
top:0px;
left:0px;
width:100px;
height:100px;
background:rgba(200,100,100,1);
line-height:100px;
text-align:center;
z-index:2;
}
.bx_shd{
position:absolute;
top:7px;
left:7px;
width:90px;
height:90px;
background:rgba(0,0,0,0.4);
z-index:1;
box-shadow:1px 2px 3px 2px rgba(0,0,0,0.4);
-webkit-transform:rotateZ(2deg) skewX(6deg) skewY(2deg);
transform:rotateZ(2deg) skewX(6deg) skewY(2deg);
}
装飾 div を使えばいい?それは違う、疑似要素で影をつけなくてはいけないのだ!これは絶対だ!
というような感じで、
業界で table レイアウト全盛期の時代に、みんなそうだから普通に [DTD HTML 4.01 Transitional] でそれやっててもいいよね~というのが許せず、本来のWEBは文書なので [DTD XHTML 1.0 Strict] でなくてはいけない!もちろんTABLEは表組でしか使ってはいけないのだ、という人が…。
そこまでいかなくても、ルールや勧告 (の思想までも) を厳格にちゃんと守ろう、と考える真面目な人がいろいろ考え悩んでしんどい想いをすることになるのです。
※あくまで個人の感想です。
【失敗例 A】親 div に [z-index:2] を指定し、疑似要素 before で影を作り、[z-index:1] を指定した例です。親の上にbeforeの青く塗ったボックスが表示されています。
親にz-index値を指定したので、子の[z-index:1]がβ世界線の値になってしまったからです。
【失敗例 B】親 div に [z-index] を指定せず、疑似要素 before で影を作り、[z-index:-1] を指定した例です。親の親であるグレーのdivにも[z-index]を指定していないので、before の影ボックスはグレーよりも下に表示されてしまい、見えなくなっています。
こういうことが起こるので [z-index:-1] はどこでも好きな場所では使えない、と最近の原森含め、多くの人が思ってしまうのです。
原森も、こんな現象を初めて見た時から、絶対的な z-index による数値指定、と勘違いしていたので、これはbody をベースにした一番下にいるのだろう、などと思っていました。
時には [z-index:-1] 技は汎用的ではない、などと dis ってみたりして…。
(もっとよく調べろ自分、英語表記しか説明がないなら、翻訳して読めよ、とアドバイスしてあげたくなってしまいます)
before影さんはどこにいるのか?
仕様をよく調べてない頃の自分なら、bodyタグのすぐ上にいるんじゃないの?なんていってしまいそうになりますが…。
MDNさんの説明、今はちゃんと日本語に誰かが翻訳してくれた記事を読んだ、現在の原森はやっとわかりました。
beforeさんは、bodyのすぐ上…ではなく、グレーのすぐ下…でもなく、[section / ID = tcmb]さんの下にいます。
…って、どこやねんそれ…。
このページの場合は、『【z-index:-1 の活用】z-index:-1 を BODY タグの子以外で使う方法』という見出しタイトルがあるヘッダーや、パンくずメニューのあるフッターを含めたウインドウデザインの [article タグ / ID = book_main] ブロック(BODYの直接の子)は [z-index : 10] となっています。
つまり、bodyの子としての [article/ID=book_main] さんが [z-index : 10] 指定によって、そこをベースとした『ローカルな重ね合わせコンテキスト』(ローカルなレイヤーグループ)を作っています。
さらに、ヘッダーやフッターと兄弟となっている、記事が表示されている部分の [section タグ / ID = kizi_cont_1] ブロックは class指定で [z-index : 50] となっています。
なので、そこをベースに、また新たな『ローカルな重ね合わせコンテキスト』(ローカルなレイヤーグループ)が作られています。
【失敗例 A】の場合。
before影の『親である赤色ボック』の『親であるグレーの div 』は auto なので、赤色ボックスに [z-index:2] を指定した場合のその値は、 [section / ID = kizi_cont_1] をベースとしたグループの中のZ軸の上下表示指定となります。そこをα世界線とすれば、before影は赤色ボックスから生まれたβ世界線にいる状態となります。
赤色ボックスから新しいローカルなグル―プとなるので、beforeは親である赤色divの上に表示されました。
【失敗例 B】の場合。
グレーも赤色も auto の状態の場合は、before の [z-index:-1] はやはり [section / ID = kizi_cont_1] をベースとしたグループの中のZ軸の上下表示指定となるので、考察してきた仕様から、親である赤色の親であるグレーのすぐ下に表示されている…
とおもってしまいがちになりますが、実は、[ID = kizi_cont_1] の子として、微妙に透明なグリーンの背景色が指定されている [section / ID = tcmb] という親の親の親が [z-index:auto] の状態で存在しているのです。
つまり、beforeさんは、[ID = kizi_cont_1]のすぐ上(※z-index:-1だから)で、その子である透明なグリーンの [section / ID = tcmb] の下にいるという状態となっているのです。
その上にはグレーのdivがいて、その上に、beforeを設定したはずの親である赤色divが表示されている、そんな感じになってます。
下のサンプルは、【失敗例 B】のグレーの背景色をアニメで透明にしています。beforeの方は塗りだけ赤色 [background:rgba(255,0,0,1)] にして、変形やbox-shadowは省略しました。ですが、真っ赤ではなく、微妙に薄い赤色になっています。それは半透明グリーン(ID:tcmb)が上にいるからです。
解決策
と言うことで、解決策は [z-index:-1] は新たな『ローカルな重ね合わせコンテキスト』(ローカルなレイヤーグループ)が作られたそのすぐ上に表示される。つまり、グレーの上に表示したければ、グレーから新たな『ローカルな重ね合わせコンテキスト』(ローカルなレイヤーグループ)が作られるようにすればいい、ということになります。つまり、グレーに[z-index:数値]を指定し、赤色は[auto](z-indexの指定なし)のままにすればよい、ということになります。
HTMLソース
<div class="grybx">
<div class="bx_min5">z-index:指定なし</div>
</div>
CSSソース
.grybx{
position:relative;
top:0;
left:0;
width:180px;
height:150px;
background:rgba(200,200,200,1);
z-index:1;
}
.bx_min5{
position:absolute;
top:0px;
left:0px;
width:100px;
height:100px;
background:rgba(200,100,100,1);
line-height:100px;
text-align:center;
}
.bx_min5:before{
content:"";
position:absolute;
top:7px;
left:7px;
width:90px;
height:90px;
background:rgba(255,0,0,1);
background:rgba(0,0,200,1);
box-shadow:1px 2px 3px 2px rgba(0,0,0,0.4);
-webkit-transform:rotateZ(2deg) skewX(6deg) skewY(2deg);
transform:rotateZ(2deg) skewX(6deg) skewY(2deg);
z-index:-1;
}
おまけ:親にz-indexを指定して兄弟とずらして重ねて表示させたい時はどうしたらいいのか?
以下のサンプルに影を付けたいという場合です。
実際にそんなことをしたいのかどうかは置いておいて、こんな場合にはまず、実験として、-1影を付ける赤緑青のタグボックスにはz-indexを指定せず、簡単に、ソースの記述順で上下の表示をさせてみました。
それぞれの親の影ではなく、影たちが下に表示されて、緑の上に赤の影が乗る、というような演出になっていません。
これは紫の親から作られたローカルな重ね合わせコンテキストにまず、[z-index:-1]のbefore黄色影の三つがソースの書き順で配置され、その上に [z-index] を指定してない赤と緑と青の親たちが書き順で配置されているからです。
下から [緑の影] → [緑] → [赤の影] → [赤] → [青の影] → [青] と表示したいけれど、[緑の影] [赤の影] [青の影] → [緑] [赤] [青] と表示されてしまっているのです。
やはりこういう場合はコンテナー div さんを使うしかないかと思います。
(それを余計なタグと考えるかどうかですが…)
もっと理由づけしたければ、コンテナー section さんでこれらは記事の節ブロックなんです、という意味を与えてもいいかと思います。
紫っぽい親 div の子として、section が親と全く同じサイズの透明なレイヤー用として3枚用意してあり、それぞれ、 [z-index:2] [z-index:1] [z-index:3] の指定で上下に重なるようにしています。
それぞれの『ローカルな重ね合わせコンテキスト』、つまりは section の子として、before に -1 影を設定したdivタグが表示されている状態となっています。
つまり、
一つ一つのローカルなグループは、section を枠として、-1 before 影の上に divボックスを表示。
それら、[section + div + before] のグループが三つ、Z軸方向に section タグに指定してある z-index値の順で重なって表示されている、という作り方となります。
HTMLソース
<div class="a_exbx">
<section class="bx_sc" style="z-index:2;"><div class="bxbxs ex_a1">z-index なし</div></section>
<section class="bx_sc" style="z-index:1;"><div class="bxbxs ex_a2">z-index なし</div></section>
<section class="bx_sc" style="z-index:3;"><div class="bxbxs ex_a3">z-index なし</div></section>
</div>
CSSソース
.a_exbx{
display:inline-block;
position:relative;
top:0;
left:0;
width:180px;
min-height:200px;
background:rgba(200,150,200,1);
z-index:2;
}
.bx_sc{
display:inline-block;
position:absolute;
top:0;
left:0;
width:180px;
min-height:200px;
}
.bxbxs{
position:absolute;
width:80px;
height:80px;
line-height:50px;
text-align:center;
}
.bxbxs:before{
content:"";
position:absolute;
bottom:-10px;
right:-10px;
width:80px;
height:80px;
background:rgba(200,200,0,1);
z-index:-1;
}
.ex_a1{
top:0px;
left:0px;
background:rgba(200,100,100,1);
}
.ex_a2{
top:20px;
left:70px;
background:rgba(100,200,100,1);
}
.ex_a3{
top:60px;
left:40px;
background:rgba(100,100,200,1);
}
【z-index:-1】影で演出して重ねた例【サンプル】
beforeで立体影を演出して、top値 left値を調節して重ねてみた例です。
[z-index:-1]を好きな場所に使う方法のまとめ
疑似要素(before , after) に[z-index:-1] を使いたい場合は、【疑似要素の親であるタグA】には [z-index:auto] または[z-index指定なし] にして『新たなローカルな重ね合わせコンテキスト(ローカルなレイヤーグループ)』を作らせないようにして、親タグよりも疑似要素 (before・after) が [z-index:-1] で下に表示されるようにする。
【タグA】の親である【タグB】 に [z-index:数値(なんでもいい)] を指定してそこから『新たなローカルな重ね合わせコンテキスト(ローカルなレイヤーグループ)』を作ってグループ化すると、 [-1影] のようなものを演出したボックスを、コンテンツの好きな場所に配置して使えるようになる、ということになります。
※ [z-index] を指定して『新たなローカルな重ね合わせコンテキスト』を作らせるための親タグは『position が static 以外のもの』にしておく必要があります。
以上、長い記事を最後まで読まれたみなさん、お疲れさまでした。
ページトップへ