「z-index」が効かないのには理由がある

「z-index」の値を大きく指定しても、他要素の下から抜け出せない事は時々経験します。 それはバグではなく、必ず理由があると考えた方が良い。

 

ネットを調べると「position: relative」を指定してみろと書かれている事が多いが、「position: static」以外の指定にしていても、「z-index」が効果しない場合の解決方法ついて、判り易い説明は見つけ難いと感じます。

 

以下に、そんな場合の主要と思われる理由と解決方法を、私の知る限りで説明します。 複雑な構成のデザインで「z-index」 で困った場合に役立つと思います。

 

 

シンプルなモデル

下はシンプルなモデルのHTMLです。 A,B,Dの3つのブロック要素があり、Bには入れ子でCが入っています。

 

<html><body>
    <div id="A">表示要素A</div>
    <div id="B">表示要素B
        <div id="C">表示要素C</div>
    </div>
    <div id="D">表示要素D</div>
</body></html>

 

CSSでデザインの体を整えますが、要点は CがBからはみ出して上下のA,Dにかかっている様なデザインです。

 

body {
    background: #eee; }

#A {
    position: absolute;
    top: 50px;
    left: 100px;
    height: 100px;
    width: 400px;
    border: 1px solid #000;
    background: #fff;
    z-index: a; }

#B {
    position: absolute;
    top: 200px;
    left: 100px;
    height: 100px;
    width: 400px;
    border: 1px solid #000;
    background: #fff;
    z-index: b; }

#C {
    position: absolute;
    top: -100px;
    left: 100px;
    height: 300px;
    width: 200px;
    border: 1px solid #000;
    background: #96c3e3;
    z-index: c; }

#D {
    position: absolute;
    top: 350px;
    left: 100px;
    height: 100px;
    width: 400px;
    border: 1px solid #000;
    background: #fff;
    z-index: d; }

 

全てのブロックは「position: absolute」で自在に配置場所を変えられます。 ここで、「z-index」のテストをしますが、望む結果は下図の様に要素Cを要素A,Dの前面にする事として説明します。

 

 

HTMLの記述順位によりz-indexが無効に見える

下図の左側は「a=2,b=2,d=2」「c=0」を指定した例です。

 

 

要素Cの下端が要素Bに隠れています。 Cを表に出したい時、誰しもCのz-indexが足りないと最初に考えて、真ん中の様に「c=10」を指定したり「c=10000」などとしてみますが、一向に効きません。 これは、HTMLで要素B→Dの順に記述すると、後のDが上に表示される規則があるからです。 b,dが同じ「2」である限り、Bとその中のCを表示した後に(上に)、Dが表示されます。

 

この場合は、Dのz-indexをBより下げる事で、右側の様にCを表に出す事が出来ます。 そもそも、HTMLの表示順を無効にするのがz-indexです。 注意すべきは「c=0」でも「d=1」のDより上に表示される事です。「z-index」は「順位階層」内での前後順を指定するもので、グローバルな効力を持つ値ではありません。

(注:「順位階層」は私の造語です)

 

順位階層で表示の前後が決まる

下図の左側は「a=3,b=2,d=1」「c=0」を指定した例です。 要素Aが要素Cを隠していて、Cを表に出したい場合です。

 

 

やはり、真ん中の様に「c=10」としてもCは表に出ません。 HTMLの記述順でBが後ですが、Aに「a=3」の指定があるので当然です。 これはAのz-indexをB以下にする事で、右側の様に解決します。

 

この状態は、要素Cの前後順が要素Bに委ねられ、要素Aと要素Bのz-indexで前後が決定されています。 要素Cにとって、自分の基盤(HTMLとしては親側になります)の階層で、自分の表示の前後が決まる様に見え、この階層の事を順位階層と言っています。

 

以上の説明はシンプルなモデル上で、なんの事はない様に思われるかも知れませんが、実際に複雑な入れ子で構成され、要素配置が交錯したデザインでは、順位階層を確認しない限り「z-index」を操作出来ない場合に直面します。

 

実際のCSS編集では、「z-index」を手当たりに変更して、力技で解決する事が多いのですが、本当は順位階層を見渡す図を書けば間違いなく操作出来、他要素の思わぬ消失を防げるでしょう。

 

 

順位階層はどこにあり前後順位はどの様にして決まるか

判り易くするために「順位階層」という造語を用いていますが、2つの要素の前後関係が決定される場所という意味です。 ある要素が他要素の背後になり、その要素の「z-index」を変えても効果が無い場合、その要素の「順位階層」を見渡すのが近道です。

 

では、「順位階層」はどこを探せば良いのか。 「順位階層」は、前後関係が問題になっている2要素のHTML上で最初の共通の親の階層です。 入れ子構造の場合は、両者を包括する最初の親で、共通の親がなければ「body」になります。

 

前後を問題にする相手要素が別の場合は、「順位階層」は違った場所になり得ることにも注意が要ります。 LとMの順位階層は、LとNの順位階層と違う場合もあります。

 

そして2要素の前後の順位は、この「順位階層」から見て、2要素のそれぞれに最も下位で指定された「z-index」が決定します。(下位とは最も順位階層に近い層です)

下図は、説明のために作ったモデルです。

 

 

要素のBlueとLgreenの前後順位を考える場合は、Redが最初の共通の親ですから、この場合の「順位階層」となります。 この場合、両者の前後はOrangeの「z-index:1」とGreenの「z-index:3」で決まります。

 

上のモデルのHTMLとCSSは以下で、適宜にプロパティを変更して試します。

 

<html><body>
<div id="Red">表示要素Red
    <div id="Gray">表示要素Gray
        <div id="Orange">表示要素Orange
            <div id="Blue">表示要素Blue</div>
         </div>
    </div>
    <div id="Green">表示要素Green
        <div id="Lgreen">表示要素Lgreen</div>
    </div>
</div>
</body></html>

 

body {
    margin:0;
    padding:0;
    background: #eee; }

#Red {
    position: relative;
    margin: 50px;
    height: 460px;
    width: 560px;
    border: 4px solid #e80606;
    background: #fff; }

#Gray {
    margin: 20px 20px;
    height: 380px;
    width: 250px;
    background: #aaa;  }

#Orange {
    position: absolute;
    top: 0;
    left: 0;
    margin: 80px 40px;
    height: 300px;
    width: 210px;
    background: #ffd54f;
    z-index: 1; }

#Blue {
    position: absolute;
    top: 0;
    left: 0;
    margin: 40px 20px;
    height: 220px;
    width: 170px;
    background: #2196f3;
    z-index: 5; }

#Green {
    position: absolute;
    top: 80px;
    left: 320px;
    height: 320px;
    width: 220px;
    background: #5ea851;
    z-index: 3; }

#Lgreen {
    margin: 20px;
    height: 220px;
    width: 180px;
    background: #8df018; }

 

●ここで、DevToolsでBlueとLgreenの要素を寄せてみると、Blueは確かにGreenとLgreenの下になっています。 順位を決定しているのは、それぞれの最下位で指定されたOrangeとGreenのz-indexです。

 

 

●Orangeを「z-index:3」として、右側のGreenとLgreenを寄せて見ます。 OrangeとGreenのz値が同じになりましたが、HTMLの記述順で後のGreenが上のままです。

 

 

●Orangeを「z-index:4」まで上げて、始めてGreenより上になりました。

 

 

但し、GreenはGrayより上にある事を注意してください。 Grayは「position未指定」=「position: static」、z-indexは「auto」として扱われています。 これは厳密には「position: absolute」などの「z-index: 0」よりも前後順が下です。

 

●ここまで、BlueとOrangeは前後順を常にOrangeが決定して来ました。 その結果GreenがOrengeとBlueの間に入る事はなく、そういうデザインは出来ない様に見えます。 しかし方法はあります。 Orangeに「position: static」を指定し、順位決定をする能力を無くせば良いのです。 その結果、この「順位階層」で自身の「z-index:5」がBlueの前後順位を決定する様になります。 

 

 

「static」を指定されたOrangeはGrayと同様に、Greenの背後になり、Blueだけを前面に出す事が出来ました。

 

 

最後にまとめとして

ある程度「z-index」に慣れた人が困るのは、上記の「順位階層」がどこにあり、そこで順位を決定している「z-index」がどの要素に指定されているかを、判断出来ない場合が殆どではないでしょうか。 このページの考え方は、そんな場合に有効です。

 

なお、スタックレベル・スタック文脈の概念と、私の造語「順位階層」の概念は、別のものです。「順位階層」の考え方は、実際のHTMLを扱っていて「z-index」の問題に直面した経験から、私自身が行き着いた経験則です。 おそらくスタック文脈などの理屈から「順位階層」の考え方を証明する事は出来ると思います。 しかしこれは、より直接に簡単に問題解決を得る事を目的としたものです。