重ね合わせコンテキストのサンプル

サンプル1

まずは、以下のような構造の HTML で実例を見ていきます。

  • <body> 要素
    • DIV #1
      • DIV #2
    • DIV #3
      • DIV #4

実際のHTMLと最初の時点のCSSは下記のとおりです。

<body>
    <div id="div1">
        <br /><span class="bold">DIV #1</span>
        <br />position: relative;
        <div id="div2">
            <br /><span class="bold">DIV #2</span>
            <br />position: absolute;
        </div>
    </div>
    <br />
    <div id="div3">
        <br /><span class="bold">DIV #3</span>
        <br />position: relative;
        <div id="div4">
            <br /><span class="bold">DIV #4</span>
            <br />position: absolute;
        </div>
    </div>
</body>
.bold {
    font-weight: bold;
    font: 12px Arial;
}
#div1,
#div3 {
    height: 80px;
    position: relative;
    border: 1px dashed #669966;
    background-color: #ccffcc;
    padding-left: 5px;
}
#div2 {
    opacity: 0.8;
    position: absolute;
    width: 150px;
    height: 200px;
    top: 20px;
    left: 170px;
    border: 1px dashed #990000;
    background-color: #ffdddd;
    text-align: center;
}
#div4 {
    opacity: 0.8;
    position: absolute;
    width: 200px;
    height: 100px;
    top: 65px;
    left: 50px;
    border: 1px dashed #000099;
    background-color: #ddddff;
    text-align: left;
    padding-left: 10px;
}

このサンプルでは、<body> 要素の子要素の <div> 要素はいずれも z-index の指定はありませんので、唯一の重ね合わせコンテキストはルート要素のみということになります。

そのため、重ね合わせ順は「あとから登場したものが手前」という順に並びます。

この状態から、DIV #2 とDIV #4 に z-index プロパティを追加してみます。

<body>
    <div id="div1">
        <br /><span class="bold">DIV #1</span>
        <br />position: relative;
        <div id="div2">
            <br /><span class="bold">DIV #2</span>
            <br />position: absolute;
            <br />z-index: 20;
        </div>
    </div>
    <br />
    <div id="div3">
        <br /><span class="bold">DIV #3</span>
        <br />position: relative;
        <div id="div4">
            <br /><span class="bold">DIV #4</span>
            <br />position: absolute;
            <br />z-index: 10;
        </div>
    </div>
</body>
.bold {
    font-weight: bold;
    font: 12px Arial;
}
#div1,
#div3 {
    height: 80px;
    position: relative;
    border: 1px dashed #669966;
    background-color: #ccffcc;
    padding-left: 5px;
}
#div2 {
    opacity: 0.8;
    position: absolute;
    width: 150px;
    height: 200px;
    top: 20px;
    left: 170px;
    border: 1px dashed #990000;
    background-color: #ffdddd;
    text-align: center;
    z-index: 20;
}
#div4 {
    opacity: 0.8;
    position: absolute;
    width: 200px;
    height: 100px;
    top: 65px;
    left: 50px;
    border: 1px dashed #000099;
    background-color: #ddddff;
    text-align: left;
    padding-left: 10px;
    z-index: 10;
}

この場合、重ね合わせコンテキストがどのような状態になっているかというと、下記のようなツリー構造になっています。

  • ルートの重ね合わせコンテキスト
    • DIV #2 ( z-index 20 )
    • DIV #4 ( z-index 10 )

DIV #1 と DIV #3 については、z-index が指定されていないので、独自の重ね合わせコンテキストは持たず、ルートの重ね合わせコンテキストに吸収された形になっています。

サンプル2

今度は、もう少し重ね合わせコンテキストの階層が深くなった例を示します。ただ、HTML の構造的には、サンプル1と大差なく、以下のような構造になっています。

  • <body> 要素
    • DIV #1
      • DIV #2
    • DIV #3
      • DIV #4

HTML と CSS のソースは以下のとおりです。

<body>
    <div id="div1">
        <br /><span class="bold">DIV #1</span>
        <br />position: relative;
        <div id="div2">
            <br /><span class="bold">DIV #2</span>
            <br />position: absolute;
            <br />z-index: 10;
        </div>
    </div>
    <br />
    <div id="div3">
        <br /><span class="bold">DIV #3</span>
        <br />position: relative;
        <br />z-index: 1;
        <div id="div4">
            <br /><span class="bold">DIV #4</span>
            <br />position: absolute;
            <br />z-index: 20;
        </div>
    </div>
</body>
.bold {
    font-weight: bold;
    font: 12px Arial;
}
#div1 {
    height: 80px;
    position: relative;
    border: 1px dashed #669966;
    background-color: #ccffcc;
    padding-left: 5px;
}
#div2 {
    opacity: 0.8;
    position: absolute;
    width: 150px;
    height: 200px;
    top: 20px;
    left: 170px;
    border: 1px dashed #990000;
    background-color: #ffdddd;
    text-align: center;
    z-index: 10;
}
#div3 {
    height: 100px;
    position: relative;
    border: 1px dashed #669966;
    background-color: #ccffcc;
    padding-left: 5px;
    z-index: 1;
}
#div4 {
    opacity: 0.8;
    position: absolute;
    width: 200px;
    height: 100px;
    top: 65px;
    left: 50px;
    border: 1px dashed #000099;
    background-color: #ddddff;
    text-align: left;
    padding-left: 10px;
    z-index: 20;
}

この例で、z-index だけを見ると、DIV #4 ( z-index 20 ) が最前面に来そうですが、実際には、DIV #2 ( z-index 10 ) が最前面に来ています。

これは、重ね合わせコンテキストが下記のようになっているためです。

  • ルートの重ね合わせコンテキスト
    • DIV #2 ( z-index 10 )
    • DIV #3 ( z-index 1 )
      • DIV #4 ( z-index 20 )

この場合、同列に並んでいるのは DIV #2 と DIV #3 なので、この両者で z-index の値が評価され、結果、DIV #2 が前面に来ています。DIV #4 はあくまでも、DIV #3の重ね合わせコンテキストの中に含まれるので、いくら z-index の値が大きくても、DIV #3と同列or上位の重ね合わせコンテキストに影響を与えることはありません。

サンプル3

このパターンは、Webサイトの『メニュー』を構成する際によく見かけられるパターンで、メニューが階層的になっており、メニューをポイントするとサブメニューが出てきて・・・というケースです。

この場合、元のメニューとサブメニューが位置的に重なり合わないデザインであれば、特に気にする必要もないですが、デザインの都合上、サブメニューとその親のメニューが位置的に重なるような場合、z-index をうまくコントロールしないと、表示したいサブメニューが隠れてしまうケースが出てきます。

まずは、サブメニューが隠れてしまうパターンの例を示します。

<body>
    <div class="lev1">
        <span class="bold">LEVEL #1</span>
        <div id="container1">
            <div class="lev2">
                <br /><span class="bold">LEVEL #2-1</span>
                <br />z-index: 1;
                <div id="container2">
                    <div class="lev3"><span class="bold">LEVEL #3-1</span></div>
                    <div class="lev3"><span class="bold">LEVEL #3-1</span></div>
                    <div class="lev3"><span class="bold">LEVEL #3-1</span></div>
                    <div class="lev3"><span class="bold">LEVEL #3-1</span></div>
                    <div class="lev3"><span class="bold">LEVEL #3-1</span></div>
                </div>
            </div>
            <div class="lev2">
                <br /><span class="bold">LEVEL #2-2</span>
                <br />z-index: 1;
                <div id="container2">
                    <div class="lev3"><span class="bold">LEVEL #3-2</span></div>
                    <div class="lev3"><span class="bold">LEVEL #3-2</span></div>
                    <div class="lev3"><span class="bold">LEVEL #3-2</span></div>
                    <div class="lev3"><span class="bold">LEVEL #3-2</span></div>
                    <div class="lev3"><span class="bold">LEVEL #3-2</span></div>
                </div>
            </div>
        </div>
    </div>
    <div class="lev1">
        <span class="bold">LEVEL #1</span>
    </div>
    <div class="lev1">
        <span class="bold">LEVEL #1</span>
    </div>
    <div class="lev1">
        <span class="bold">LEVEL #1</span>
    </div>
</body>
body{
    margin: 2.0rem;
}
div { font: 12px Arial; }
span.bold { font-weight: bold; }
div.lev1 {
    width: 250px;
    height: 70px;
    position: relative;
    border: 2px outset #669966;
    background-color: #ccffcc;
    padding-left: 5px;
}
#container1 {
    z-index: 1;
    position: absolute;
    top: 30px;
    left: 75px;
}
div.lev2 {
    opacity: 0.9;
    width: 200px;
    height: 60px;
    position: relative;
    border: 2px outset #990000;
    background-color: #ffdddd;
    padding-left: 5px;
}
#container2 {
    z-index: 1;
    position: absolute;
    top: 20px;
    left: 110px;
}
div.lev3 {
    z-index: 10;
    width: 100px;
    position: relative;
    border: 2px outset #000099;
    background-color: #ddddff;
    padding-left: 5px;
}

この例では、LEVEL #1 の各要素に関しては、position: relative; が指定されているだけなので、重ね合わせコンテキストは作成されていません。

それに対して、LEVEL #2 の各要素は、LEVEL #1の各要素より手前に表示するために、z-index を指定しています。ここまではうまく行っているのですが、本来は LEVEL #2の全要素よりも手前に表示したい、LEVEL #3-1 の一部の要素は、LEVEL #2-2の要素の裏に隠れてしまっています。

これは、LEVEL #3-1 の各要素は、LEVEL #2-1 の重ね合わせコンテキストの中に含まれる形になるので、z-index の値をいくら大きくしても、LEVEL #2-1 と LEVEL #2-2 の重ね合わせ順に沿って表示されることになるので、LEVEL #3-1 の各要素は LEVEL #2-2 よりも裏側に表示されてしまいます。

この手のメニューは、何らかのプログラム処理で、動的に出力されることが多いですが、そういった場合に、同じ階層の要素に同じクラス名を付与して、そのクラス名に対してスタイルを指定する、というパターンで実装していると、このサンプルのような事態が発生します。

対処の仕方は、実際のデザインの仕方によっても変わってくるので、一概にコレが正解、というものはありませんが、この例の場合であれば、LEVEL #2 の各要素の クラス名やIDの振り方、スタイルシートでの z-index 値の指定の仕方を工夫して対処します。

以下に対処例を示しますが、これは以下の前提が成り立つ場合に限った対処法です。

  • LEVEL #3の各要素は、後続のLEVEL #2の要素と重なり合う場合があるが、先行のLEVEL #2の各要素と重なることは無い
  • LEVEL #3-1とLEVEL #3-2が同時に表示されることはない

<body>
    <div class="lev1">
        <span class="bold">LEVEL #1</span>
        <div id="container1">
            <div class="lev2" id="lev2-1">
                <br /><span class="bold">LEVEL #2-1</span>
                <br />z-index: 4;
                <div id="container2">
                    <div class="lev3"><span class="bold">LEVEL #3-1</span></div>
                    <div class="lev3"><span class="bold">LEVEL #3-1</span></div>
                    <div class="lev3"><span class="bold">LEVEL #3-1</span></div>
                    <div class="lev3"><span class="bold">LEVEL #3-1</span></div>
                    <div class="lev3"><span class="bold">LEVEL #3-1</span></div>
                </div>
            </div>
            <div class="lev2" id="lev2-2">
                <br /><span class="bold">LEVEL #2-2</span>
                <br />z-index: 3;
                <div id="container2">
                    <div class="lev3"><span class="bold">LEVEL #3-2</span></div>
                    <div class="lev3"><span class="bold">LEVEL #3-2</span></div>
                    <div class="lev3"><span class="bold">LEVEL #3-2</span></div>
                    <div class="lev3"><span class="bold">LEVEL #3-2</span></div>
                    <div class="lev3"><span class="bold">LEVEL #3-2</span></div>
                </div>
            </div>
            <div class="lev2" id="lev2-3">
                <br /><span class="bold">LEVEL #2-3</span>
                <br />z-index: 2;
            </div>
            <div class="lev2" id="lev2-4">
                <br /><span class="bold">LEVEL #2-4</span>
                <br />z-index: 1;
            </div>
        </div>
    </div>
    <div class="lev1">
        <span class="bold">LEVEL #1</span>
    </div>
    <div class="lev1">
        <span class="bold">LEVEL #1</span>
    </div>
    <div class="lev1">
        <span class="bold">LEVEL #1</span>
    </div>
</body>
body{
    margin: 2.0rem;
}
div { font: 12px Arial; }
span.bold { font-weight: bold; }
div.lev1 {
    width: 250px;
    height: 70px;
    position: relative;
    border: 2px outset #669966;
    background-color: #ccffcc;
    padding-left: 5px;
}
#container1 {
    z-index: 1;
    position: absolute;
    top: 30px;
    left: 75px;
}
div.lev2 {
    opacity: 0.9;
    width: 200px;
    height: 60px;
    position: relative;
    border: 2px outset #990000;
    background-color: #ffdddd;
    padding-left: 5px;
}
#lev2-1{
    z-index: 4;
}
#lev2-2{
    z-index: 3;
}
#lev2-3{
    z-index: 2;
}
#lev2-4{
    z-index: 1;
}
#container2 {
    z-index: 1;
    position: absolute;
    top: 20px;
    left: 110px;
}
div.lev3 {
    z-index: 10;
    width: 100px;
    position: relative;
    border: 2px outset #000099;
    background-color: #ddddff;
    padding-left: 5px;
}

この例では、LEVEL #2の各要素にそれぞれ固有のIDを振り、そのIDに対して『登場順の逆順』になるように、z-index の値を指定しています。

そうすることで、先に登場した LEVEL #2の要素が後続のLEVEL #2の各要素の裏に回ることはないので、結果として、LEVEL #2の子要素であるLEVEL #3の各要素が後続のLEVEL #2の裏に回り込むことが回避できる…というわけです。

ただ、何らかのプログラムでメニューを生成しているような場合は、LEVEL #2に当たる要素が何個あるか、予めわかっているわけではありませんので、その部分の工夫も必要になってくるでしょう。

 


このサイトでは、CSSのセレクタ・プロパティなどの定義は下記サイトを参考にしています。
MDN Web Docs: https://developer.mozilla.org/ja/
W3C仕様の正確な定義、最新情報は上記サイトをご覧ください。
CSSのプロパティがどのブラウザに対応しているのかは、下記のサイトで確認できます。
Can I Use?: https://caniuse.com/#home

コメント

タイトルとURLをコピーしました