CSS知らないとハマり続けるfloatboxの貫通問題

HTML/CSSコーディング

CSSでデザインしてて、「あれっ」と思うこと。親要素の中にfloatした子要素を入れると子要素の高さが親要素の高さに反映されず貫通して表示されてしまう問題。基本的なことですが一応整理しておかないといつまでもハマり続けたりするので備忘録を。

floatした要素の高さは親用素には反映されない

例えば以下のようなHTML。


<div id="wrapper">
<p>親要素</p>
<div id="inboxA"><p>内包要素A</p></div>
<div id="inboxB"><p>内包要素B</p></div>
</div>

idがwrapperという親要素の中に「親要素」というテキスト、idがinboxAとinboxBという3つの要素が内包されているとします。

このinboxA,Bにそれぞれfloatがかかるよう次のようなCSSを適用してみます。


#wrapper{
width:240px;
padding:5px;
background-color:#888;
}
#inboxA{
display:block;
float:left;
width:100px;
background-color:#f00;
}
#inboxB{
display:block;
float:right;
width:100px;
background-color:#0f0;
}

で、実際ブラウザで表示して見ると

サンプルページ

はい、このように内包している子要素が親要素を貫通して外に飛び出してしまいます。

これはバグではなくCSSの仕様を正しく解釈するブラウザでは必ずこのように表示されます。floatした子要素の高さは無視して親要素をレンダリングするのが正しい解釈なのです。

これを回避するにはどうすればよいか?内包する子要素として、floatを解除した要素をもう一つ追加すればよいのです。

例えば


<div id="wrapper">
<p>親要素</p>
<div id="inboxA"><p>内包要素A</p></div>
<div id="inboxB"><p>内包要素B</p></div>
<div id="dummy"></div>
</div>

最初のHTMLにidがdummyというdiv要素を1行追加しました。これに


#wrapper{
width:240px;
padding:5px;
background-color:#888;
}
#inboxA{
display:block;
float:left;
width:100px;
background-color:#f00;
}
#inboxB{
display:block;
float:right;
width:100px;
background-color:#0f0;
}
#dummy{
display:block;
clear:both;
}

このようなCSSを適用します。inboxBまでは元のCSSと同じで、dummy要素に関するプロパティを追加し、このなかで回り込みの解除(clear:both;)を行っています。すると

サンプルページ

子要素としてfloatされていないdiv要素が一つ追加されたわけですから、親要素の高さはこのdiv子要素までを内包するものとしてレンダリングされます。結果としてきちんと親要素の中に子要素全てが包含されているように描画されます。

しかしこれではHTMLとしてはイマイチです。なんの内容も含まないdiv要素(id=dummy)が存在するということは文章構造としては無意味でインバリッド(則法的ではない)です。

ではどうすればよいでしょう?

HTMLは冒頭の通りとし余計なダミー要素を追加しないで、CSSの方でafter擬似要素を追加すればいいのです。冒頭のHTMLに対し


#wrapper{
width:240px;
padding:5px;
background-color:#888;
}
#inboxA{
display:block;
float:left;
width:100px;
background-color:#f00;
}
#inboxB{
display:block;
float:right;
width:100px;
background-color:#0f0;
}
#wrapper:after{
content:"";
display:block;
clear:both;
}

このようなCSSを適用します。

一番最後で親要素#wrapperに対してafter擬似要素を追加しています。これによってHTMLには存在しない子要素が親要素内の最後尾に追加されたものとブラウザは解釈します。

contentは""としてなんの内容も含みません。この擬似要素に対してclear:both;を適用することで、親要素の高さはそこまでを考慮して描画されるようになります。

サンプルページ

実に単純なことですが、知らないといつまでも解決付かないことなんですよね、これって。

この手法は「clearfix」といってfloat解除の常套手段なのですが、そもそもHTMLもCSSもそんなに詳しくない人間にとってはそんな手法(あるいはfloatの仕様)は知らないし、まして「clearfix」なんて言葉も知らないわけですから検索でもなかなか解決方法にたどり着かない方もいるでしょう。

まとめ

あらためてネスト構造のBOXの描画方法について極簡単に書いて見ました。

途中で紹介しているdummy要素を追加する方法、「どうせ描画されないんだからそれはそれでいいジャマイカ」と言う気もしますが、必ずしもビジュアルで情報を入手し得ない場合(例えば音声ブラウザやテキストブラウザなど)にはある程度HTMLが則法的でないと無意味な要素を「これは空です」なんて表示や読みあげをしてしまっては、伝えるべきものも伝わらないで混乱を招きますからね。ケースとしては決して多くはないと思いますが…

なおcleafixのCSSの書き方はcontentにモノスペースやコロンを挿入してhiddenで描画しないようにしたりする方法もあちこちで紹介されてます。これはIE旧バージョンに対するハックであったりしますが、ここで説明すると余計ワケわかんなくなったりするのであえて割愛しました。興味のある方は「clearfix」でググって見てください。いろいろと文献が出てきますので。

んじゃまた。

コメント

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