CSSの配置と重なり
同じ二つの箱をblock・inline・inline-blockへ変更し、relative・absolute・fixedの座標を測ります。後半では二つの親子グループを重ね、どの要素が手前にあるかを調べます。rectは境界の座標と寸法を小数2桁で返す関数です。
説明
CSSの配置では、通常の流れに沿って場所を確保する要素と、そこから外れて配置される要素があります。positionは位置の基準や場所の確保に関わり、z-indexは重なる順序に関わります。高いz-indexを付けても、親の重なりの範囲を越えられるとは限りません。
同じ二つの箱をblock・inline・inline-blockへ変更し、relative・absolute・fixedの座標を測ります。後半では二つの親子グループを重ね、どの要素が手前にあるかを調べます。rectは境界の座標と寸法を小数2桁で返す関数です。
1blockの通常配置
幅300pxの親へ二つの箱を並べます。
(globalThis.doc=createFormDocument二つの箱を持つ表示文書('<!doctype html><html lang="ja"><head><style>body{font:16px/24px system-ui;margin:16px;background:#111;color:#eee}#container{width:300px;background:#222}.item{padding:4px;background:#22434b}#b{background:#57304a}</style></head><body><div id="container"><div id="a" class="item">A</div><div id="b" class="item">B</div></div></body></html>'),globalThis.a=doc.getElementById("a"),globalThis.b=doc.getElementById("b"),{a:rect("#a")Aの座標と寸法,b:rect("#b")Bの座標と寸法})二つのblockは縦に並び、親の使える幅を埋めます。後ろのBはAの高さの分だけ下に配置されます。この通常の流れが、位置指定を加える前の基準になります。
2inlineではwidthが同じ意味で効かない
両方をinlineにし、width=120pxも指定します。
(a.style.display=b.style.display="inline"同じ行のインラインへ,a.style.width=b.style.width="120px"幅を指定して効果を測る,{a:rect("#a"),b:rect("#b")})二つは同じ行へ並びますが、通常の非置換inline要素の幅は120pxにはなりません。内容とインラインの配置によって幅が決まります。widthを書けば、どのdisplayでも同じ大きさになるわけではありません。
3inline-blockで幅を持たせる
displayだけをinline-blockへ変えます。
(a.style.display=b.style.display="inline-block"同じ行に置く箱へ変更,{a:rect("#a"),b:rect("#b")})それぞれの内容幅120pxに左右paddingが加わり、境界幅は約128pxです。同じ行に置きながら箱として寸法を指定できます。inlineとinline-blockで、同じwidth宣言の結果が異なります。
4relativeは元の場所を残す
Aを通常位置から右へ30px、下へ10pxずらします。
(globalThis.beforeB=rect("#b"),a.style.position="relative"通常位置を基準にする,a.style.left="30px",a.style.top="10px"表示位置をずらす,{a:rect("#a"),bBefore:beforeB,bAfter:rect("#b")Bの場所は維持})Aの表示位置は変わりますが、Bの座標は変わりません。relativeは通常の流れで確保した場所を残したまま、見える位置をずらします。
5absoluteは通常の流れから外れる
親を位置指定の基準にし、Aをその左上へ置きます。
(doc.getElementById("container").style.position="relative"親を配置の基準にする,a.style.position="absolute"Aを通常配置から外す,a.style.left="0",a.style.top="0"基準の左上へ,{a:rect("#a"),b:rect("#b")})Aが通常の流れから外れたため、BはAの元の場所へ詰まります。この例ではposition:relativeの親がabsoluteの包含ブロックになります。transformなど、他の指定が包含ブロックを作る場合もあります。
6fixedの基準
Aをfixedへ変え、left=20px、top=30pxとします。
(a.style.position="fixed"表示領域を基準に固定,a.style.left="20px",a.style.top="30px"指定する座標,rect("#a"))この文書では、Aは表示領域の左から約20px、上から約30pxです。通常はfixedが表示領域を基準にしますが、祖先のtransformなどによって基準が変わる場合があるため、fixedなら常に文書の最上位が基準と決めつけないようにします。
7非表示でも場所が残る場合
Bのvisibilityをhiddenにした場合と、displayをnoneにした場合を比較します。
(b.style.visibility="hidden"場所を残して非表示,globalThis.hiddenRect=rect("#b"),b.style.display="none"レイアウトの箱を作らない,{hidden:hiddenRect,none:rect("#b")})visibility:hiddenでは箱の寸法が残り、display:noneでは境界の寸法が0になります。見えないという結果が同じでも、周囲のレイアウトへ与える影響は異なります。
8二つの重なりのグループ
ここからは二つの親子グループを重ねます。親Aはz-index=1、親Bは2です。
(doc.querySelector("style").textContent+="#stage{position:relative;width:240px;height:120px}.layer{position:absolute;width:180px;height:90px}.tile{position:absolute;width:120px;height:60px;padding:4px}#layerA{left:0;top:0;z-index:1}#layerB{left:40px;top:20px;z-index:2}#one{z-index:999;background:#22434b}#two{z-index:1;background:#57304a}",doc.body.innerHTML=重なりを調べる二つの親子グループ'<div id="stage"><div id="layerA" class="layer"><div id="one" class="tile">Aの子</div></div><div id="layerB" class="layer"><div id="two" class="tile">Bの子</div></div></div>',{front:hit("#stage",60,40)重なる点の手前の要素,childA:styleOf("#one","z-index"),parentA:styleOf("#layerA","z-index"),parentB:styleOf("#layerB","z-index")})重なる点で手前にあるのはtwo、つまりBの子です。Aの子の999はAのスタッキングコンテキスト内の順序であり、親Aの1を越えて親Bの2より手前へ出る値ではありません。
9子のz-indexだけを増やす
Aの子を9999へ上げます。
(doc.getElementById("one").style.zIndex="9999"Aの内部で子の順序を上げる,hit("#stage",60,40))手前はtwoのままです。子の値を大きくするだけでは、別の親のスタッキングコンテキストとの順序を変えられません。
10親の順序を変える
親Aをz-index=3へ上げます。
(doc.getElementById("layerA").style.zIndex="3"親の重なり順を変更,hit("#stage",60,40))今度はoneが手前になります。二つのグループ間の順序を変えるには、比較されている親側の順序を変更する必要がありました。
11autoでは同じ境界を作らない
親Aのz-indexをautoへ戻します。
(doc.getElementById("layerA").style.zIndex="auto"親の明示的な重なり順を外す,hit("#stage",60,40))このabsoluteの親Aは、z-index:autoだけでは先ほどのスタッキングコンテキストを作りません。Aの子の9999が外側の比較に関わり、oneが手前になります。
12opacityでも境界ができる
親Aにopacity=0.9を指定します。
(doc.getElementById("layerA").style.opacity="0.9"透明度による重なりの境界,hit("#stage",60,40))twoが再び手前になります。1未満のopacityもスタッキングコンテキストを作るためです。z-indexだけでなく、祖先のopacityやtransformなども重なりの切り分けで確認します。
まとめ
通常配置で確保する場所と表示位置を分け、relative・absolute・fixedの基準を確認します。
非表示でもvisibilityとdisplayでは場所の残り方が異なります。
重なりはスタッキングコンテキストごとに決まり、子の大きなz-indexだけでは親同士の順序を越えられません。
操作履歴と解説を振り返れます。
ブラウザ / HTML・DOM
(globalThis.doc=createFormDocument('<!doctype html><html lang="ja"><head><style>body{font:16px/24px system-ui;margin:16px;background:#111;color:#eee}#container{width:300px;background:#222}.item{padding:4px;background:#22434b}#b{background:#57304a}</style></head><body><div id="container"><div id="a" class="item">A</div><div id="b" class="item">B</div></div></body></html>'),globalThis.a=doc.getElementById("a"),globalThis.b=doc.getElementById("b"),{a:rect("#a"),b:rect("#b")}){
"a": {
"x": 16,
"y": 16,
"width": 299.99,
"height": 31.99
},
"b": {
"x": 16,
"y": 47.98,
"width": 299.99,
"height": 31.99
}
}<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/24px system-ui;margin:16px;background:#111;color:#eee}#container{width:300px;background:#222}.item{padding:4px;background:#22434b}#b{background:#57304a}
:root{}body{}</style></head><body inert><div id="container"><div id="a" class="item">A</div><div id="b" class="item">B</div></div></body></html>(a.style.display=b.style.display="inline",a.style.width=b.style.width="120px",{a:rect("#a"),b:rect("#b")}){
"a": {
"x": 16,
"y": 14.34,
"width": 18.46,
"height": 26.64
},
"b": {
"x": 34.46,
"y": 14.34,
"width": 18.19,
"height": 26.64
}
}<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/24px system-ui;margin:16px;background:#111;color:#eee}#container{width:300px;background:#222}.item{padding:4px;background:#22434b}#b{background:#57304a}
:root{}body{}</style></head><body inert><div id="container"><div id="a" class="item" style="display: inline; width: 120px;">A</div><div id="b" class="item" style="display: inline; width: 120px;">B</div></div></body></html>(a.style.display=b.style.display="inline-block",{a:rect("#a"),b:rect("#b")}){
"a": {
"x": 16,
"y": 16,
"width": 127.98,
"height": 31.99
},
"b": {
"x": 143.98,
"y": 16,
"width": 127.98,
"height": 31.99
}
}<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/24px system-ui;margin:16px;background:#111;color:#eee}#container{width:300px;background:#222}.item{padding:4px;background:#22434b}#b{background:#57304a}
:root{}body{}</style></head><body inert><div id="container"><div id="a" class="item" style="display: inline-block; width: 120px;">A</div><div id="b" class="item" style="display: inline-block; width: 120px;">B</div></div></body></html>(globalThis.beforeB=rect("#b"),a.style.position="relative",a.style.left="30px",a.style.top="10px",{a:rect("#a"),bBefore:beforeB,bAfter:rect("#b")}){
"a": {
"x": 45.99,
"y": 26,
"width": 127.98,
"height": 31.99
},
"bBefore": {
"x": 143.98,
"y": 16,
"width": 127.98,
"height": 31.99
},
"bAfter": {
"x": 143.98,
"y": 16,
"width": 127.98,
"height": 31.99
}
}<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/24px system-ui;margin:16px;background:#111;color:#eee}#container{width:300px;background:#222}.item{padding:4px;background:#22434b}#b{background:#57304a}
:root{}body{}</style></head><body inert><div id="container"><div id="a" class="item" style="display: inline-block; width: 120px; position: relative; left: 30px; top: 10px;">A</div><div id="b" class="item" style="display: inline-block; width: 120px;">B</div></div></body></html>(doc.getElementById("container").style.position="relative",a.style.position="absolute",a.style.left="0",a.style.top="0",{a:rect("#a"),b:rect("#b")}){
"a": {
"x": 16,
"y": 16,
"width": 127.98,
"height": 31.99
},
"b": {
"x": 16,
"y": 16,
"width": 127.98,
"height": 31.99
}
}<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/24px system-ui;margin:16px;background:#111;color:#eee}#container{width:300px;background:#222}.item{padding:4px;background:#22434b}#b{background:#57304a}
:root{}body{}</style></head><body inert><div id="container" style="position: relative;"><div id="a" class="item" style="display: inline-block; width: 120px; position: absolute; left: 0px; top: 0px;">A</div><div id="b" class="item" style="display: inline-block; width: 120px;">B</div></div></body></html>(a.style.position="fixed",a.style.left="20px",a.style.top="30px",rect("#a")){
"x": 20,
"y": 30,
"width": 127.98,
"height": 31.99
}<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/24px system-ui;margin:16px;background:#111;color:#eee}#container{width:300px;background:#222}.item{padding:4px;background:#22434b}#b{background:#57304a}
:root{}body{}</style></head><body inert><div id="container" style="position: relative;"><div id="a" class="item" style="display: inline-block; width: 120px; position: fixed; left: 20px; top: 30px;">A</div><div id="b" class="item" style="display: inline-block; width: 120px;">B</div></div></body></html>(b.style.visibility="hidden",globalThis.hiddenRect=rect("#b"),b.style.display="none",{hidden:hiddenRect,none:rect("#b")}){
"hidden": {
"x": 16,
"y": 16,
"width": 127.98,
"height": 31.99
},
"none": {
"x": 0,
"y": 0,
"width": 0,
"height": 0
}
}<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/24px system-ui;margin:16px;background:#111;color:#eee}#container{width:300px;background:#222}.item{padding:4px;background:#22434b}#b{background:#57304a}
:root{}body{}</style></head><body inert><div id="container" style="position: relative;"><div id="a" class="item" style="display: inline-block; width: 120px; position: fixed; left: 20px; top: 30px;">A</div><div id="b" class="item" style="display: none; width: 120px; visibility: hidden;">B</div></div></body></html>(doc.querySelector("style").textContent+="#stage{position:relative;width:240px;height:120px}.layer{position:absolute;width:180px;height:90px}.tile{position:absolute;width:120px;height:60px;padding:4px}#layerA{left:0;top:0;z-index:1}#layerB{left:40px;top:20px;z-index:2}#one{z-index:999;background:#22434b}#two{z-index:1;background:#57304a}",doc.body.innerHTML='<div id="stage"><div id="layerA" class="layer"><div id="one" class="tile">Aの子</div></div><div id="layerB" class="layer"><div id="two" class="tile">Bの子</div></div></div>',{front:hit("#stage",60,40),childA:styleOf("#one","z-index"),parentA:styleOf("#layerA","z-index"),parentB:styleOf("#layerB","z-index")}){
"front": "two",
"childA": "999",
"parentA": "1",
"parentB": "2"
}<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/24px system-ui;margin:16px;background:#111;color:#eee}#container{width:300px;background:#222}.item{padding:4px;background:#22434b}#b{background:#57304a}#stage{position:relative;width:240px;height:120px}.layer{position:absolute;width:180px;height:90px}.tile{position:absolute;width:120px;height:60px;padding:4px}#layerA{left:0;top:0;z-index:1}#layerB{left:40px;top:20px;z-index:2}#one{z-index:999;background:#22434b}#two{z-index:1;background:#57304a}
:root{}body{}</style></head><body inert><div id="stage"><div id="layerA" class="layer"><div id="one" class="tile">Aの子</div></div><div id="layerB" class="layer"><div id="two" class="tile">Bの子</div></div></div></body></html>(doc.getElementById("one").style.zIndex="9999",hit("#stage",60,40))"two"<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/24px system-ui;margin:16px;background:#111;color:#eee}#container{width:300px;background:#222}.item{padding:4px;background:#22434b}#b{background:#57304a}#stage{position:relative;width:240px;height:120px}.layer{position:absolute;width:180px;height:90px}.tile{position:absolute;width:120px;height:60px;padding:4px}#layerA{left:0;top:0;z-index:1}#layerB{left:40px;top:20px;z-index:2}#one{z-index:999;background:#22434b}#two{z-index:1;background:#57304a} :root{}body{}</style></head><body inert><div id="stage"><div id="layerA" class="layer"><div id="one" class="tile" style="z-index: 9999;">Aの子</div></div><div id="layerB" class="layer"><div id="two" class="tile">Bの子</div></div></div></body></html>
(doc.getElementById("layerA").style.zIndex="3",hit("#stage",60,40))"one"<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/24px system-ui;margin:16px;background:#111;color:#eee}#container{width:300px;background:#222}.item{padding:4px;background:#22434b}#b{background:#57304a}#stage{position:relative;width:240px;height:120px}.layer{position:absolute;width:180px;height:90px}.tile{position:absolute;width:120px;height:60px;padding:4px}#layerA{left:0;top:0;z-index:1}#layerB{left:40px;top:20px;z-index:2}#one{z-index:999;background:#22434b}#two{z-index:1;background:#57304a} :root{}body{}</style></head><body inert><div id="stage"><div id="layerA" class="layer" style="z-index: 3;"><div id="one" class="tile" style="z-index: 9999;">Aの子</div></div><div id="layerB" class="layer"><div id="two" class="tile">Bの子</div></div></div></body></html>
(doc.getElementById("layerA").style.zIndex="auto",hit("#stage",60,40))"one"<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/24px system-ui;margin:16px;background:#111;color:#eee}#container{width:300px;background:#222}.item{padding:4px;background:#22434b}#b{background:#57304a}#stage{position:relative;width:240px;height:120px}.layer{position:absolute;width:180px;height:90px}.tile{position:absolute;width:120px;height:60px;padding:4px}#layerA{left:0;top:0;z-index:1}#layerB{left:40px;top:20px;z-index:2}#one{z-index:999;background:#22434b}#two{z-index:1;background:#57304a} :root{}body{}</style></head><body inert><div id="stage"><div id="layerA" class="layer" style="z-index: auto;"><div id="one" class="tile" style="z-index: 9999;">Aの子</div></div><div id="layerB" class="layer"><div id="two" class="tile">Bの子</div></div></div></body></html>
(doc.getElementById("layerA").style.opacity="0.9",hit("#stage",60,40))"two"<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'"><style>:root{color-scheme:dark}body{margin:16px;background:#111;color:#eee;font:14px/1.6 system-ui}body::after{content:"";display:block;height:calc(100vh - 32px)}a{color:#80c4d6}table{border-collapse:collapse}th,td{border:1px solid #555;padding:4px 8px}img{max-width:100%}body{font:16px/24px system-ui;margin:16px;background:#111;color:#eee}#container{width:300px;background:#222}.item{padding:4px;background:#22434b}#b{background:#57304a}#stage{position:relative;width:240px;height:120px}.layer{position:absolute;width:180px;height:90px}.tile{position:absolute;width:120px;height:60px;padding:4px}#layerA{left:0;top:0;z-index:1}#layerB{left:40px;top:20px;z-index:2}#one{z-index:999;background:#22434b}#two{z-index:1;background:#57304a} :root{}body{}</style></head><body inert><div id="stage"><div id="layerA" class="layer" style="z-index: auto; opacity: 0.9;"><div id="one" class="tile" style="z-index: 9999;">Aの子</div></div><div id="layerB" class="layer"><div id="two" class="tile">Bの子</div></div></div></body></html>
演習完了