ボックスの配置

目次

ボックスは

という三つの配置体系(positioning scheme)によって、どのように配置されるかが決まります。以下では三つの配置体系と、配置されたボックスの位置を相対的に動かす相対位置決め、ボックスの重なりについて説明します。

  1. ボックスの配置
  2. 通常フロー
    1. ブロック整形文脈
    2. インライン整形文脈
  3. フロート
    1. フロートのクリア
  4. 絶対位置決め
    1. 絶対配置
    2. 固定配置
  5. 相対位置決め
  6. ボックスの重なり

ボックスの配置

ボックスの配置を決めるのが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なら左右逆)。

  1. フロートを通常フローから取り除き、左外辺が包含ブロックの左辺か別の左フロートの左外辺に接するまで左に移動する。
  2. 行ボックスがあるなら、フロートの上外辺を行ボックスの上辺に揃える。
  3. 水平方向にフロートを収めるスペースがないなら、フロートを下に押し下げる。
  4. フロートは通常フローに属さないため、位置決めされていないブロックボックスはフロートが存在していないかのように、垂直に配置される。
  5. 行ボックスの幅はフロートの幅を確保するために短くなる。
  6. フロートに続く内容は、フロートの右の行ボックスに流し込む。
  7. フロートの直前の行に含まれる内容は、フロートの右の行ボックスに流し込む。
  8. 短縮された行ボックスが内容を収めるのには短すぎるなら、その内容を下に押し下げる。
  9. 通常フローに新しいブロック整形文脈を設置する要素、置換ブロックレベル要素、表要素(display:table)のボックスのマージンは、同ブロック内にあるどのフロートとも重なってはいけない。(必要なら、それらの要素をフロートの下に押し下げる。)

フロートはブロックボックスとなり、新たなブロック整形文脈を形成します。フロートの中は通常フロー配置となります。

float:noneの場合はフロートになりません。

例1
<p>
<span>floating box</span>
最初の段落です。フロートの幅の分だけ
行ボックスが短くなっているのが分かる
と思います。
</p>
<p>
ここが次の段落です。この段落でも行ボックスの
短縮が起こります。
</p>
span {
 float: left;
 width: 5em; height: 10em;
 border: 1px solid blue }
p { border: 1px solid red }

(図)フロートの説明1

注目したい点は、フロートがない場合でもp要素のボックスが図と同じように配置されることです。一つめのボックスがフロートを含めるように長くなったり、次のボックスがフロートと重ならないよう下に下がったりはしません。フロートは通常フローからは取り除かれているからです。

例2
<p>
フロートの前の内容です。
<span>floating box</span>
フロートの後の内容です。
</p>
span {
 float: left;
 width: 5em; height: 5em;
 border: 1px solid blue }
p { border: 1px solid red }

(図)フロートの説明2

上記のルール7により、フロートの直前の行の内容がフロートの右に流し込まれています。

例3
<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
}

(図)フロートの説明3

「Supercalifragilisticexpialidocious」はフロートの右に流し込むには行ボックスが短すぎます。そのため、上記のルール8によりフロートの下へ移動します。

例4
<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 }

(図)フロートの説明4

左フロートが連続する場合、後続するフロートは先行するフロートの左外辺に接するまで移動します。(ルール1)

例5
<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
}

(図)フロートの説明5

上とほぼ同じコードですが、p要素をwidth:9emとしたため、フロートを二つ横に並べることができなくなりました。そのため、ルール3により後続するフロートが先行するフロートの下に押し下げられています。

フロートにはさらに厳密なルールが定められています(float:leftの場合、float:rightなら左右逆)。便宜上、これを厳密ルールと呼ぶことにします。

  1. 左フロートの左外辺は包含ブロックの左辺より左にならない。
  2. 現在のボックスが左フロートであり、かつソース文書中で前にある要素によって生成される左フロートがあるなら、それぞれの先行ボックスについて、現在のボックスの左外辺は先行ボックスの右外辺より右でなければならない、もしくは上外辺が先行ボックスの下外辺より下でなければならない。
  3. 左フロートの右外辺は、その右にある右フロートの左外辺より右にはならない。
  4. フロートの上外辺は包含ブロックの上辺より上にはならない。フロートが相殺される二つのマージンの間にあるとき、フロートはそのフローにある空の匿名ブロックボックスを親に持っているものとして配置される。
  5. フロートの上外辺は、ソース文書中で前にある要素により生成されるブロックボックスやフロートの上外辺よりも上にならない。
  6. フロートの上外辺は、ソース文書中で前にある要素により生成されるボックスを含む行ボックスの上辺よりも上にならない。
  7. 左に別の左フロートを持つ左フロートは、その右外辺が包含ブロックの右辺よりも右にならない。
  8. フロートはできるだけ上に配置しなければならない。
  9. 左フロートはできるだけ左に配置しなければならない。より左に配置することよりも、上に配置することを優先する。
  10. clearプロパティが宣言されたフロートの上外辺は、clear:leftの場合は先行する全ての左フロートの下外辺よりも下、clear:rightの場合は右フロートの下外辺よりも下、clear:bothの場合はどちらのフロートの下外辺よりも下でなければならない。

フロートを利用して段組を組むときは、この厳密なルールをよく理解しておくことが必要になります。

例6
<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により包含ブロックの上辺に一致します。

(図)boxA、boxB、boxCが横に並ぶ

例7
<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の下に配置されます。

(図)boxA、boxBが横に並び、boxCはboxAの下に位置する

CSS 2ではフロートは何らかの方法で幅が明示されていなければならないという規定がありましたが、CSS 2.1でこの規定は削除されました。フロートがwidth:autoのとき、フロートは「内容に合わせて縮めた幅」を持つとされています。

フロートのクリア

フロートのクリアにはclearプロパティを使います。これもまた「回り込みの解除」とよく説明されるのですが、正確にはそうではありません。

  1. clear:leftが指定された要素のボックスの上外辺は、ソース文書中で前にある要素が生成する左フロートの下外辺より下に位置する。(clear:rightの場合は右フロートの下外辺よりも下。)
  2. clear:bothが指定された要素のボックスの上外辺は、ソース文書中で前にある要素が生成するどのフロートの下外辺よりも下に位置する。

clearプロパティが適用されるのはブロックレベル要素のみです。

clearプロパティが指定された要素のボックスは、margin-topプロパティによる上マージンの量がそのボックスをフロートより下に位置させるには不十分なとき、クリアランス(clearance)と呼ばれる空白が必要な量だけ上マージンの上に加えられます。

例1
<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がフロートより下に位置するには上マージンだけで十分なので、クリアランスは挿入されません。

(図)boxBの上には6emのマージンのみ

例2
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がフロートの下にならないため、クリアランスが挿入されます。

(図)boxBの上にはクリアランスと3emのマージン

clearプロパティは、それが指定された要素の中にあるフロートや、別のブロック整形文脈にあるフロートとは関係しません。

例3
<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より下に位置することはありません。

(図)clearボックスはboxBの中にある

例4
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ボックスはboxAのより下になる

clearプロパティを使ったら謎の空白ができた」というような場合、この例のようになっている可能性が高いでしょう。

絶対位置決め

positionプロパティが"absolute"か"fixed"である要素を絶対位置決めされた要素(absolutely positioned element)と言います。絶対位置決めには

の二つがあります。絶対位置決めされた要素は通常フローから完全に取り除かれます。

絶対配置

position:absoluteが指定された要素のボックスは、包含ブロックからtopプロパティかbottomプロパティ、leftプロパティかrightプロパティで指定されたオフセット量の分だけ移動した位置に配置されます。

position:absoluteが指定された要素の包含ブロックは、直近の祖先要素で位置決めされた(positionプロパティが"static"以外)ボックスのパディング辺です。そのようなボックスがなければ、初期包含ブロックが包含ブロックとなります。

例1
<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要素は初期包含ブロックの右上

例2
span {
position: absolute;
top: 0;
right: 0;
border: 1px solid red
}
div {
 position: relative;
 border: 1px solid blue
}
body { padding: 10px }

div要素が位置決めされているため、絶対配置されたspan要素の包含ブロックはdiv要素の生成するボックスのパディング辺となります。

(図)span要素はdiv要素のボックスの右上

固定配置

position:fixedが指定された要素のボックスも、包含ブロックからtopプロパティかbottomプロパティ、leftプロパティかrightプロパティで指定されたオフセット量の分だけ移動した位置に配置されます。

position:fixedが指定された要素の包含ブロックは、「連続」グループのメディアであれば表示域サイズの長方形、「ページ」グループのメディアであればページボックスです。つまり、ブラウザであればウィンドウをスクロールしても表示域は移動しないためボックスは固定して表示され、プリンタで印刷するのであれば各ページの同じ位置にボックスが出力されます。

相対位置決め

通常フローで配置されたボックスやフロートは、position:relativeを指定すると相対的に位置を変化させることができます。これを相対位置決め(relative positioning)と言います。相対位置決めは他のボックスの配置には全く影響を与えず、相対位置決めされていない他のボックスは相対位置決めされたボックスがそうされていない場合と同じ場所に位置します。

オフセット量はtopプロパティ、bottomプロパティ、leftプロパティ、rightプロパティで指定します。算出値は次のように導出します。

<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要素のボックスが移動する前と同じ位置に配置されます。

(図)span要素のボックスが下に2em、左に5em移動

ボックスの重なり

ボックスは水平・垂直方向に加えて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
 }

上の例は以下のように表示されます。

(図)上からstack2-1(z-index:1), stac2(z-index:2), stack1-1(z-index:3), stack1(z-index:1)

まず、ルート要素(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

スタック文脈をさらに詳しく見ると、次のようになります。

  1. スタック文脈を設置する要素の背景とボーダー
  2. 負のスタックレベルを持つ子孫要素のスタック文脈
  3. 通常フローにある非インラインレベル要素の子孫要素を含むスタックレベル
  4. フロートとその内容のスタックレベル
  5. 通常フローにあるインラインレベル要素の子孫のスタックレベル
  6. z-index:autoz-index:0である位置決めされた子孫要素のスタックレベル
  7. 正のスタックレベルを持つ子孫要素のスタック文脈

仕様書ではAppendix E. Elaborate description of Stacking Contextsにさらに詳しい説明があります。

Information

現在の位置