ボックスは
という三つの配置体系(positioning scheme)によって、どのように配置されるかが決まります。以下では三つの配置体系と、配置されたボックスの位置を相対的に動かす相対位置決め、ボックスの重なりについて説明します。
ボックスの配置を決めるのがposition
プロパティです。
static
relative
absolute
fixed
position
プロパティの値が"static
"以外の要素を位置決めされた(positioned)要素と言います。position:static
の要素は位置決めされていない(non-positioned)要素です。位置決めされたボックスのオフセット量は、top
プロパティ、bottom
プロパティ、left
プロパティ、right
プロパティによって指定します。
通常フローにあるボックスは、整形文脈に属します。整形文脈にはブロックボックスが属するブロック整形文脈と、インラインボックスが属するインライン整形文脈があります。
初期ブロックボックスはブロック整形文脈(block formatting context)に加わります。ブロック整形文脈の中では、ブロックボックスが上から下に向って縦に積み重なってゆきます。「ブロックレベル要素は前後で改行される」などと一般に説明されているようです。ブロックボックスの左外辺は包含ブロックの左外辺に接するように配置され、ボックス間の上下の間隔はmargin
プロパティによって決まります。
フロート、絶対位置決めされた要素、インラインブロック要素、セル要素、表題要素、overflow
プロパティが"visible
"以外の要素は、新たにブロック整形文脈を設置します。
インラインボックスはインライン整形文脈(inline formatting context)に加わります。インライン整形文脈の中では、インラインボックスは包含ブロックの上から水平方向に向かって並べられます。インラインボックスを包含し行を構成する長方形の領域は行ボックス(line box)と呼ばれます。行ボックスが単一の行に収まりきらないとき、行ボックスは垂直に積み重ねられてゆきます。HTMLの説明で「右端で自動的に折り返される」などと言われているのがこの現象です。垂直方向に重ねられた行ボックスは分離されたり、重なり合ったりすることはありません。行ボックスの幅は通常包含ブロックの幅に一致しますが、間にフロートが入るせいで短縮されることがあります。
<p>このように長い文章は複数の行ボックス
にまたがって表示されます。</p>
インラインボックスが行ボックスの横幅を超えるときは、インラインボックスが分割され複数の行ボックスにまたがって割り当てられます。その際、マージン、ボーダー、パディングの効果は分割された境界面には現れません。
<p>分割された<em>インラインボックス</em>があります。</p>
em { border: 1px solid blue }
float
プロパティに"left
"か"right
"が指定された要素の生成するボックスをフロート(float)と言います。フロートは一般に「回り込み」と説明されますが、大雑把には次のような仕様になっています(float:left
の場合、float:right
なら左右逆)。
display:table
)のボックスのマージンは、同ブロック内にあるどのフロートとも重なってはいけない。(必要なら、それらの要素をフロートの下に押し下げる。)フロートはブロックボックスとなり、新たなブロック整形文脈を形成します。フロートの中は通常フロー配置となります。
float:none
の場合はフロートになりません。
<p>
<span>floating box</span>
最初の段落です。フロートの幅の分だけ
行ボックスが短くなっているのが分かる
と思います。
</p>
<p>
ここが次の段落です。この段落でも行ボックスの
短縮が起こります。
</p>
span {
float: left;
width: 5em; height: 10em;
border: 1px solid blue }
p { border: 1px solid red }
注目したい点は、フロートがない場合でもp
要素のボックスが図と同じように配置されることです。一つめのボックスがフロートを含めるように長くなったり、次のボックスがフロートと重ならないよう下に下がったりはしません。フロートは通常フローからは取り除かれているからです。
<p>
フロートの前の内容です。
<span>floating box</span>
フロートの後の内容です。
</p>
span {
float: left;
width: 5em; height: 5em;
border: 1px solid blue }
p { border: 1px solid red }
上記のルール7により、フロートの直前の行の内容がフロートの右に流し込まれています。
<p>
<span>floating box</span>
Supercalifragilisticexpialidocious
</p>
span {
float: left;
width: 5em; height: 5em;
border: solid 1px blue }
p {
width: 10em;
border: solid 1px red
}
「Supercalifragilisticexpialidocious」はフロートの右に流し込むには行ボックスが短すぎます。そのため、上記のルール8によりフロートの下へ移動します。
<p>
<span>floating box1</span>
<span>floating box2</span>
フロートの後の内容です。
</p>
span {
float: left;
width: 5em; height: 5em;
border: 1px solid blue }
p { border: 1px solid red }
左フロートが連続する場合、後続するフロートは先行するフロートの左外辺に接するまで移動します。(ルール1)
<p>
<span>floating box1</span>
<span>floating box2</span>
フロートの後の内容です。
</p>
span {
float: left;
width: 5em; height: 5em;
border: 1px solid blue }
p {
width: 9em;
border: 1px solid red
}
上とほぼ同じコードですが、p
要素をwidth:9em
としたため、フロートを二つ横に並べることができなくなりました。そのため、ルール3により後続するフロートが先行するフロートの下に押し下げられています。
フロートにはさらに厳密なルールが定められています(float:left
の場合、float:right
なら左右逆)。便宜上、これを厳密ルールと呼ぶことにします。
clear
プロパティが宣言されたフロートの上外辺は、clear:left
の場合は先行する全ての左フロートの下外辺よりも下、clear:right
の場合は右フロートの下外辺よりも下、clear:both
の場合はどちらのフロートの下外辺よりも下でなければならない。フロートを利用して段組を組むときは、この厳密なルールをよく理解しておくことが必要になります。
<div id="container">
<div id="boxA">boxA</div>
<div id="boxB">boxB</div>
<div id="boxC">boxC</div>
</div>
div#container {
width: 300px;
overflow: auto;
border: 2px solid black
}
div#boxA {
float: left;
width: 50px;
background: #ffcfce
}
div#boxB {
float: left;
width: 150px; background: #cecfff
}
div#boxC {
float: left;
width: 100px;
background: #ceffce
}
boxA、boxB、boxCの包含ブロックの幅は300pxであり、各ボックスを横に並べるとちょうど収まります。このような場合、厳密ルール1によりboxAの左外辺が包含ブロックの左辺に重なり、厳密ルール2、8、9によりboxBとboxCが横に並べられます。boxA、boxB、boxCの上外辺は厳密ルール8、4、5により包含ブロックの上辺に一致します。
<div id="container">
<div id="boxA">boxA</div>
<div id="boxB">boxB</div>
<div id="boxC">boxC</div>
</div>
div#container {
width: 250px;
overflow: auto;
border: 2px solid black
}
div#boxA {
float: left;
width: 50px;
background: #ffcfce
}
div#boxB {
float: left;
width: 150px; background: #cecfff
}
div#boxC {
float: left;
width: 100px;
background: #ceffce
}
包含ブロックの幅は250pxであり、boxA、boxBは横に並べられますが、boxCを横に並べると右にはみ出してしまいます。このような場合は厳密ルール7、8、9によりboxCがboxAの下に配置されます。
CSS 2ではフロートは何らかの方法で幅が明示されていなければならないという規定がありましたが、CSS 2.1でこの規定は削除されました。フロートがwidth:auto
のとき、フロートは「内容に合わせて縮めた幅」を持つとされています。
フロートのクリアにはclear
プロパティを使います。これもまた「回り込みの解除」とよく説明されるのですが、正確にはそうではありません。
clear:left
が指定された要素のボックスの上外辺は、ソース文書中で前にある要素が生成する左フロートの下外辺より下に位置する。(clear:right
の場合は右フロートの下外辺よりも下。)clear:both
が指定された要素のボックスの上外辺は、ソース文書中で前にある要素が生成するどのフロートの下外辺よりも下に位置する。clear
プロパティが適用されるのはブロックレベル要素のみです。
clear
プロパティが指定された要素のボックスは、margin-top
プロパティによる上マージンの量がそのボックスをフロートより下に位置させるには不十分なとき、クリアランス(clearance)と呼ばれる空白が必要な量だけ上マージンの上に加えられます。
<p id="boxA">
<span>floating box</span>
最初の段落です。フロートの幅の分だけ
行ボックスが短くなっているのが分かる
と思います。
</p>
<p id="boxB">
ここが次の段落です。
</p>
span {
float: left;
width: 5em; height: 10em;
border: 1px solid blue }
p#boxB {
clear: left;
margin-top: 6em
}
p { border: 1px solid red }
boxBにclear:left
が指定されていますが、boxBがフロートより下に位置するには上マージンだけで十分なので、クリアランスは挿入されません。
span {
float: left;
width: 5em; height: 10em;
border: 1px solid blue }
p#boxB {
clear: left;
margin-top: 3em
}
p { border: 1px solid red }
margin-top:3em
だけではboxBがフロートの下にならないため、クリアランスが挿入されます。
clear
プロパティは、それが指定された要素の中にあるフロートや、別のブロック整形文脈にあるフロートとは関係しません。
<div id="boxA">boxA</div>
<div id="boxB">
boxB
<div id="clear">clear:left</div>
boxB
</div>
div#boxA {
float: left;
width: 100px;
height: 100px;
border: 1px solid red
}
div#boxB {
float: left;
width: 100px;
height: 200px;
border: 1px solid blue
}
div#clear {
clear: left;
background-color: #afa;
border: 1px solid green
}
boxAとboxBを左フロートにすることで、横に並べています。左フロートであるboxBは新たにブロック整形文脈を設置するため、その中にあるclear:left
が指定されたボックスが別のブロック整形文脈にあるboxAより下に位置することはありません。
div#boxA {
float: left;
width: 100px;
height: 100px;
border: 1px solid red
}
div#boxB {
margin-left: 102px;
width: 100px;
height: 200px;
border: 1px solid blue
}
div#clear {
clear: left;
background-color: #afa;
border: 1px solid green
}
boxBに左マージンを取ることで、boxAとboxBを横並びにしています。このとき、boxBは新たなブロック整形文脈を設置しません。よって、boxAとclear:left
が指定されたボックスは同じブロック整形文脈にあります。したがって、clear:left
が指定されたボックスの上辺が左フロートであるboxAの下辺より下になるようクリアランスが設けられます。
「clear
プロパティを使ったら謎の空白ができた」というような場合、この例のようになっている可能性が高いでしょう。
position
プロパティが"absolute
"か"fixed
"である要素を絶対位置決めされた要素(absolutely positioned element)と言います。絶対位置決めには
position:absolute
)position:fixed
)の二つがあります。絶対位置決めされた要素は通常フローから完全に取り除かれます。
position:absolute
が指定された要素のボックスは、包含ブロックからtop
プロパティかbottom
プロパティ、left
プロパティかright
プロパティで指定されたオフセット量の分だけ移動した位置に配置されます。
position:absolute
が指定された要素の包含ブロックは、直近の祖先要素で位置決めされた(position
プロパティが"static
"以外)ボックスのパディング辺です。そのようなボックスがなければ、初期包含ブロックが包含ブロックとなります。
<body>
<div>
ここがdiv要素の中
<span>position:absolute</span>
</div>
</body>
span {
position: absolute;
top: 0;
right: 0;
border: 1px solid red
}
div { border: 1px solid blue }
body { padding: 10px }
位置決めされたボックスがないため、絶対配置されたspan
要素の包含ブロックは初期包含ブロックとなります。
span {
position: absolute;
top: 0;
right: 0;
border: 1px solid red
}
div {
position: relative;
border: 1px solid blue
}
body { padding: 10px }
div
要素が位置決めされているため、絶対配置されたspan
要素の包含ブロックはdiv
要素の生成するボックスのパディング辺となります。
position:fixed
が指定された要素のボックスも、包含ブロックからtop
プロパティかbottom
プロパティ、left
プロパティかright
プロパティで指定されたオフセット量の分だけ移動した位置に配置されます。
position:fixed
が指定された要素の包含ブロックは、「連続」グループのメディアであれば表示域サイズの長方形、「ページ」グループのメディアであればページボックスです。つまり、ブラウザであればウィンドウをスクロールしても表示域は移動しないためボックスは固定して表示され、プリンタで印刷するのであれば各ページの同じ位置にボックスが出力されます。
通常フローで配置されたボックスやフロートは、position:relative
を指定すると相対的に位置を変化させることができます。これを相対位置決め(relative positioning)と言います。相対位置決めは他のボックスの配置には全く影響を与えず、相対位置決めされていない他のボックスは相対位置決めされたボックスがそうされていない場合と同じ場所に位置します。
オフセット量はtop
プロパティ、bottom
プロパティ、left
プロパティ、right
プロパティで指定します。算出値は次のように導出します。
left:auto; right:auto
なら0left
プロパティ、right
プロパティのどちらかが"auto
"の場合、"auto
"でないプロパティの値left
プロパティ、right
プロパティがどちらも"auto
"でない場合、direction:ltr
ならleft
プロパティの値、direction:rtl
ならright
プロパティの値top:auto; bottom:auto
なら0top
プロパティ、bottom
プロパティのどちらかが"auto
"の場合、"auto
"でないプロパティの値top
プロパティ、bottom
プロパティがどちらも"auto
"でない場合、top
プロパティの値<div>
span要素の前
<span>position:relative</span>
span要素の後
</div>
span {
position: relative;
top: 2em;
right: 5em;
border: 1px solid red
}
div {
position: relative;
border: 1px solid blue
}
span
要素を相対位置決めしています。span
要素の前後の匿名インラインボックスは、span
要素のボックスが移動する前と同じ位置に配置されます。
ボックスは水平・垂直方向に加えてz軸方向の位置を持ちます。絶対位置決め、相対位置決めなどによってボックスどうしが重なるときは、z軸において上にあるボックスが前面に描画されます。
それぞれのボックスはスタック文脈(stacking context)に属しています。スタック文脈中のボックスは、同じスタック文脈の中にある他のボックスとのz軸上の位置関係を示すスタックレベル(stack level)という整数値を持ちます。スタックレベルの高いボックスほど前面に描画されます。スタックレベルが同じであるボックスは、文書ツリー上の順番にしたがって後ろから前へ積み重ねられます。
z-index
プロパティはボックスの重なりを指定するプロパティです。このプロパティは位置決めされた(position
プロパティが"static
"以外の)要素に適用されます。値には<整数値>か"auto
"を指定します。<整数値>は現在のスタック文脈中におけるスタックレベルを表し、さらに自身のスタックレベルが"0"である局所スタック文脈(local stacking context)を設置します。つまり、スタック文脈が別のスタック文脈を包含するということです。値が"auto
"であれば、現在のスタック文脈におけるスタックレベルは親要素のボックスと同じになり、新たな局所スタック文脈は設置しません。また、ルート要素はルールスタック文脈を設置します。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>Layer test</title>
</head>
<body>
<div id="stack1">
stack1(z-index:1)
<div id="stack1-1">
stack1-1(z-index:3)
</div>
</div>
<div id="stack2">
stack2(z-index:2)
<div id="stack2-1">
stack2-1(z-index:1)
</div>
</div>
</body>
</html>
div#stack1 {
z-index: 1;
width: 200px;
height: 200px;
position: absolute;
top: 0; left: 0;
background-color: #afa
}
div#stack1-1 {
z-index: 3;
width: 100px;
height: 100px;
position: absolute;
top: 70px; left: 130px;
background-color: #99f
}
div#stack2 {
z-index: 2;
width: 200px;
height: 200px;
position: absolute;
top: 100px; left: 100px;
background-color: #faa
}
div#stack2-1 {
z-index: 1;
width: 100px;
height: 100px;
position: absolute;
top: 50px; left: -50px;
background-color: #fff777
}
上の例は以下のように表示されます。
まず、ルート要素(html
要素)がルートスタック文脈を設置します。その文脈の中で、stack1のスタックレベルは1、stack2のスタックレベルは2となり、stack2がstack1より前面になります。stack2は別のスタック文脈を設置します。その文脈にあるのはstack2とstack2-1で、スタックレベルはそれぞれ0と1になります。よって、最も前面に表示されるのはstack2-1で、その次がstack2です。stack1も別のスタック文脈を設置します。その中ではstack1のスタックレベルが0、stack1-1のスタックレベルが3です。
z-index
プロパティの値は自身が属するスタック文脈におけるスタックレベルです。ですから、その値が大きければ必ず前面に表示されるというわけではありません。例えば、この例ではz-index:1
であるstack2-1の方がz-index:3
であるstack1-1よりも前になっています。
スタック文脈を設置する要素 | ||||||
---|---|---|---|---|---|---|
ルート要素 | stack1 | stack2 | stack1-1 | stack2-1 | ||
要素のスタックレベル | stack1 | 1 | 0 | |||
stack2 | 2 | 0 | ||||
stack1-1 | 3 | 0 | ||||
stack2-1 | 1 | 0 |
スタック文脈をさらに詳しく見ると、次のようになります。
z-index:auto
かz-index:0
である位置決めされた子孫要素のスタックレベル仕様書ではAppendix E. Elaborate description of Stacking Contextsにさらに詳しい説明があります。