「z-index」が効かないのには理由がある
「z-index」の値を大きく指定しても、他要素の下から抜け出せない事は時々経験します。 それはバグではなく、必ず理由があると考えた方が良い。
ネットを調べると「position: relative」を指定してみろと書かれている事が多いが、「position: static」以外の指定にしていても、「z-index」が効果しない場合の解決方法ついて、判り易い説明は見つけ難いと感じます。
以下に、そんな場合の主要と思われる理由と解決方法を、私の知る限りで説明します。 複雑な構成のデザインで「z-index」 で困った場合に役立つと思います。
シンプルなモデル
下はシンプルなモデルのHTMLです。 A,B,Dの3つのブロック要素があり、Bには入れ子でCが入っています。
CSSでデザインの体を整えますが、要点は CがBからはみ出して上下のA,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は以下で、適宜にプロパティを変更して試します。
●ここで、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」の問題に直面した経験から、私自身が行き着いた経験則です。 おそらくスタック文脈などの理屈から「順位階層」の考え方を証明する事は出来ると思います。 しかしこれは、より直接に簡単に問題解決を得る事を目的としたものです。