5. フロートの性質

最終更新 2006年5月28日


フロートを利用した段組レイアウトをするには、フロートの性質を理解する必要があります。加えて、ブラウザのバグにも対処しなければなりません。 ここでは、段組を作るさいに必要となるフロートの仕様について説明します。

フロート
float:left、または float:right が指定されたボックスを「フロート」と呼んでいます。ほかにも浮動体などと呼ばれることもあります。
float
フロートしたボックスは、通常の流し込みから取り除かれ、float:leftの場合は左に、float:rightの場合は右に寄せされる。

フロートは通常の流し込みに属さない

通常、div 要素などのブロックボックスは、コンテナブロックの最上段からソースに書かれた順番に(積み木のように)ボックスを上から下へ縦に重ねてレイアウトされます。 二つのボックスの縦の距離は上下マージンによって決まり、隣接する上下マージンは相殺し合います。これを通常の流し込み(normal flow)と呼びます。

ただし、フロートは通常の流し込みに属しません。すなわち、

例1 フロートはマージンを相殺しない

マージンの相殺
相互に隣り合っているか入れ子関係にある複数のボックス間において,間にパディングもしくはボーダー領域を挟まずに隣接するマージン同士が結合して一つのマージンになることを「マージンが相殺される」(collapsing margins)と言います。

ここでは、フロートを使ったレイアウトの場合にポイントとなりやすい「入れ子関係にあるボックス間のマージンの相殺」について説明します。

通常の流し込みにおけるマージンの相殺

<h1>見出しh1</h1>

<div>
 <h2>見出しh2</h1>
</div>
* {
 margin:0;
 padding:0;
}

h2 {
 margin-top:1em;
}

全称セレクタ(*)ですべての要素のマージンとパディングを 0 にしています。h2 の上マージンは 1em です。ただし、下のサンプルではわかりやすいように、div(黄)、h1, h2(灰)に背景色をつけてあります。

div と h2 の間のマージンの相殺をなくす(すなわち、div と h2 の間にマージンを設置する)には間にパディングかボーダーを指定します。

div {
 border-top: 1px solid;
}

フロートはマージンを相殺しない

div をフロートさせると、div と h2 の間でマージンが相殺されなくなります。

div {
 width:50%; /* floatにはwidthが必要です */
 float:left;
}

例2 フロートの前後のブロックボックス

<div id="boxA">
A
</div>

<div id="boxB">
B
</div>

<div id="boxC">
C
</div>

A, B, C の3つのボックスが縦に並んでいます。通常の流し込みではソースの順にこの3つのボックスが縦に積まれます。

つぎに、ボックスB に float を指定します。

#boxB {
 width:200px; /* floatにはwidthが必要です */
 float:left;
}

ボックスB がフロートすると、あとにつづくボックスC はボックスB が存在しないかのように流し込まれ、ボックスC の上辺がボックスA の下辺に接します(参考:ボックスBが実際に存在しない場合のサンプル)。 ただしフロートしたボックスがある場合は、ボックスC の行ボックス(テキストが表示される一行ずつのボックス)はフロートに重ならないように縮みます。

フロートとマージンによる段組

ここで、ボックスC がフロートしたボックスB に重ならないように、ボックスC に左マージンを指定してみます。

#boxC {
 margin-left:200px;
}

実はこれはフロートとマージンを利用した段組の作り方です(前回は両方のボックスをフロートさせる方法を紹介しました)。 なお、ボックスC に width を指定するとIE のバグが発現するので気をつけましょう。

例3 フロートを含むブロックボックス

つぎのような指定がある場合、どのような表示になるでしょうか。

<div id="container">

 <div id="boxA">
 A
 </div>

 <div id="boxB">
 B
 </div>

 <div id="boxC">
 C
 </div>

 <div id="boxD">
 D
 </div>

</div>
#container {
 width:600px;
 border:5px solid black;
 background:gray;
}

#boxB {
 width:30%;
 float:left;
}

#boxC {
 width:30%;
 float:left;
}

#boxD {
 width:30%;
 float:left;
}

この場合、ボックスB、C、D はフロートしているため通常の流し込みに属しません。 よって、コンテナブロック(#container)のボーダーは中身がボックスA だけであるかのように設置されます。 背景の gray もボックスA の背景に塗りつぶされ見えません(ボックスA の背景が透明なら、ボックスA の背景のみ gray になる)。

概念図

Firefox はそのとおりに表示します。 しかし IE6 はまるでフロートが通常の流し込みに属しているかのようにボーダーと背景色を表示してしまいます。 これはやはり IE6 のバグです。

Firefoxでの表示 IE6での表示

フロートは通常の流し込みに属さないということを忘れていると、フロートを使った段組レイアウトをしている場合などに表示がおかしい!ということになりかねません。 よくあるのがこの例のように、「フロートの親要素にボーダーをつけると IE6 ではフロートボックスまで囲まれているのに Firefox だとそうならない」というものです。 しかしこれは IE6 がおかしいのです。

コンテナの高さを確保するには

方法1 ボックスD で clear
#boxD {
 width:100%;
 clear:left;
}

ボックスDを float させずに clear します。 clear の特性によって、ボックスD のボーダー辺がボックスB および C の外下辺より下に来るようにボックス D の上マージンが増加します。

(この例ではボックスB、Cともに下マージンは無いため、外下辺は内容下辺と同じです。また、ボックスDにも上ボーダーはないのでボーダー辺と内容上辺は同じです。)

概念図

ボックスD で clear することで、ボックスD はボックスB、C のすぐ下に配置されます。 ボックスD は通常の流し込みに属するので、コンテナブロックの中身はボックスA とボックスD であるかのようにボーダーと背景色が表示されます。

フロートを使った段組レイアウトではフッタ(ボックスD)で clear することがよくありますが、それはこのためでもあります。

方法2 コンテナブロックに overflow

ボックスD で clear しない場合の方法です。コンテナブロックに visible(デフォルト)以外の overflow を指定すると Firefox でも IE6 と同様な表示になります。

CSS 2.1 Spec. W3C CR 25 February 2004の10.6.6にこの根拠が書かれています (CSS2 リファレンス 付録:CSS2.1 の視覚整形モデル詳細に邦訳)。

簡単に言うと、height の値が auto で overflow の値が visible 以外のブロック要素が、そのマージン下辺よりも下にくるようなフロートを子に持つならば、その高さはフロートを含むように広げられる、すなわち、フロートの親ボックスが高さの算出時に子のフロートを含めないのは、親ボックスの overflow の値が visible のときに限るのです。 って、全然簡単じゃないですね。

※overflow:scroll ではスクロールバーが出てしまいます。 また、overflow:hidden では Netscape7.1 で内容が表示されない(バグ)、overflow:auto ではMacIE5 でスクロールバーが出るようです。

方法3 コンテナブロックに float

同様にコンテナブロックがフロートである場合も、子供フロートを含むようにその高さが広げられます。

#container {
 float:left;
}
方法4 生成内容で clear
#container:after {
 content:"";
 display:block;
 clear:left;
}

コンテナブロックの後ろ(:after擬似要素)にcontentプロパティで内容を生成し、そこで clear します。 clearの適用可能要素はブロックレベル要素なので、display:block も指定します。

※IE6 は content プロパティに未対応です。

まとめ

次回