Blog

ブログ

floatとclearfixとzoom:1

2021.12.06 公開
Yuko Hashimoto
Yuko Hashimoto デザイナー

横並びレイアウトにfloatを使っていました

HTMLで横並びレイアウトを行う際、最近はFlexboxCSSグリッドレイアウトを使用しますね。
すごく便利ですよね。しかし、どちらもここ数年、モダンブラウザがメインになって普及してきた書き方です。(AndroidのChromeもプレフィクスが面倒くさかったり、割とバグがあったのであまり気軽に使えなかったりしました)

Flexboxが広まる前はどうしていたのかというと、floatプロパティを使うのが主流で、その前はtableを使ったり、positionプロパティを駆使して頑張ったりしていました。
もう最近はtableでレイアウトを頑張ることはないと思いますが、floatはまだまだ使われていることがあります。

最近CSSを学び始めた方が数年前に実装されたCSSを扱う際、floatで作られた横並びレイアウトを見ると「何だこれ? なんでこうなってるの?」となるかもなあと思っています。結構クセがあるので、原理を理解して使用しないと振り回され過ぎて無駄なスタイル表記が増えて行きがちかもしれない……。

また、いろんな記事で「floatでレイアウトしたらclearfixを使おう!」とよく紹介されています。このclearfixも時代ごとに何種類もあって混乱したり、なぜこれが必要なのかが初心者の方には伝わりにくいかなあと思い、この記事を書きました。

CSSでのレイアウトの歴史はこの記事が詳しいです。
HTMLやCSSのレイアウトの歴史を振り返る – Qiita

そもそも、floatとは

詳しい仕様はこちら。
float – CSS: カスケーディングスタイルシート | MDN

float は CSS のプロパティで、要素を包含ブロックの左右どちらかの側に沿うように設置し、テキストやインライン要素がその周りを回りこめるように定義します。要素はウェブページの通常のフローから外れますが、 (絶対位置指定とは対照的に) フローの一部であり続けます。

難しい言い回しをしてますが、要はもともと回り込みレイアウトに使うためのプロパティです。floatを設定した(=floatがnoneではない)要素は浮動要素(floating element) となります。displayはblockです。

例えばこのようにスタイル指定すると、画像のように回り込んで表示されます。

<div style="width:300px;">
  <img src="neko.jpg" alt="ねこ" style="float:left; width:100px;">
  <p>ネコチャンカワイイ!ネコチャンkawaii!<br>ネコチャンネコチャン!ネコチャンカワイイネエ!!!オイデオイデコッチオイデネコチャン!!!</p>
</div>
floatした画像に文字が回り込んだ例
画像(float:left)に対して文字(pタグ)が回り込んでいる

HTML4のalign属性をCSSでやるために定義されたプロパティだったような…(うろ覚え)

floatで横並びレイアウトを作る

floatプロパティの回り込みを利用して横並びレイアウトを作るとこんな感じです。

<div style="width:100%; height:100px;">
  <div style="float:left; width:40%; background:pink; height:100px;">
    float: left の要素
  </div>
  <div style="float:left; width:60%; background:aqua; height:100px;">
    float: left の要素
  </div>
</div>
floatで横並びレイアウトを作った図
横並びになった

上の例では全部の要素にheightを設定しましたが、横並びの段組でHTMLを作る場合は要素の高さが決まっていないことが多いですよね。
左袖メニューと本文の組み合わせが一番多いんじゃないかな。あと、横幅が100%ではないこともあります。

ということで、heightを消し、横幅をウィンドウ幅より小さい固定値にしてみると……。

<div style="width:400px;">
  <div style="float:left; width:40%; background:pink;">
    float: left の要素<br>ああああああ<br>あああ<br>ああああ
  </div>
  <div style="float:left; width:60%; background:aqua;">
    float: left の要素<br>
  </div>
</div>
<p>横並びってどないやねん</p>
<p>横並びってどないやねん</p>
<p>横並びってどないやねん</p>
<p>横並びってどないやねん</p>
回り込みによって横並びが崩れた図
横並び、崩壊

float要素を包んだ一番外側の親要素以降のpタグ要素まで、どんどん左側に並んでいきます。

ちなみに親要素のdivは中身に浮動要素しか入っていないので、高さ0になります。

chromeで検証すると親要素の高さ0
chromeで検証してみた時の表示

親要素はwidthとheightそれぞれ指定した方向にしか実体がなくて、内部の子要素はそこから飛び出しているイメージです。表現が難しい。

float指定された子要素に対して後の要素が回り込むので、親要素の高さがない時は子要素の横に後のp要素が回り込み、親要素に高さがある時はその部分を避け、はみ出ている子要素の横に回り込むようになります。

回り込んでいる状態の説明図
float未指定の親要素の範囲には回り込めないが、親要素の中身は浮動要素なので高さ指定した部分しか実体として描画されず、はみ出した子要素に対して後の要素が回り込む

しかしメニューと本文ブロックの組み合わせでこういうことが起きると大変ですよね。

floatでの回り込みの解除でわかりにくくなるポイント

なんでfloatでレイアウトするとこんなに壊れるんや! わからん! となるポイントはこの辺かなあと思います。

これらを少し意識しながら回り込み解除の方法を説明します。

回り込み解除をやってみる

floatを解除するには、clear:bothを設定します。

例えばこちらは最初にやったシンプルな回り込み。

<div style="width:300px;">
  <img src="neko.jpg" alt="ねこ" style="float:left; width:100px;">
  <p>ネコチャン</p>
  <p>clear:bothしてないよ</p>
</div>
 
<div style="width:300px;">
  <img src="neko.jpg" alt="ねこ" style="float:left; width:100px;">
  <p>ネコチャン</p>
  <p style="clear:both;">clear:bothしたよ</p>
</div>
画像に文字が回り込む例と、回り込み解除した例
clear:bothによる回り込み解除

同じように、横並びレイアウトでも、横並び要素の最後の要素の次の要素にclear:bothを指定するといい感じになります。
clear:bothを指定した要素以降が全て回り込み解除される様子は文書作成ソフトと同じです。

上の画像だと、猫の画像と「ネコチャン」の文字が横並びで、「clear:bothしたよ」のブロックで回り込み解除されています。この「clear:bothしたよ」のブロックを空の状態で作るとこんな感じ。この要素以降の回り込みを解除しつつ、回り込みなしのブロック要素として親要素のお尻に置くことで、親要素の描画範囲を確定しています。

<div style="width:400px;">
  <div style="float:left; width:40%; background:pink;">
    float: left の要素<br>ああああああ<br>あああ<br>ああああ
  </div>
  <div style="float:left; width:60%; background:aqua;">
    float: left の要素<br>
  </div>
  <div style="clear:both;"></div><!-- 回り込み解除のための空要素 -->
</div>
<p>横並びってどないやねん</p>
<p>横並びってどないやねん</p>
<p>横並びってどないやねん</p>
<p>横並びってどないやねん</p>

次は横並び要素を包んだ親要素の次の要素で回り込み解除した場合。文書作成ソフトと一番感覚が近いのはこちらですね。

<div style="width:400px;">
  <div style="float:left; width:40%; background:pink;">
    float: left の要素<br>ああああああ<br>あああ<br>ああああ
  </div>
  <div style="float:left; width:60%; background:aqua;">
    float: left の要素<br>
  </div>
</div>
<p style="clear:both;">横並びってどないやねん</p><!-- 回り込み解除 -->
<p>横並びってどないやねん</p>
<p>横並びってどないやねん</p>
<p>横並びってどないやねん</p>

浮動要素を内包するブロック要素(親要素)の描画範囲の実体を与えることで解決したい場合、親要素に子要素より大きい高さを指定できればOKです。
親要素以降の要素が回り込んで来ず、横並びの段組に見せることができます。

<div style="width:400px; height:100px;"><!-- 高さ指定 -->
  <div style="float:left; width:40%; background:pink;">
    float: left の要素<br>ああああああ<br>あああ<br>ああああ
  </div>
  <div style="float:left; width:60%; background:aqua;">
    float: left の要素<br>
  </div>
</div>
<p>横並びってどないやねん</p>
<p>横並びってどないやねん</p>
<p>横並びってどないやねん</p>
<p>横並びってどないやねん</p>

さらに、ブロック整形コンテキストとしてfloat以外のプロパティを指定することでも解除できます。詳細はリンク先を参照してください。
(下のコードはoverflowを指定した場合)

<div style="width:400px; overflow:hidden;"><!-- overflow指定 -->
  <div style="float:left; width:40%; background:pink;">
    float: left の要素<br>ああああああ<br>あああ<br>ああああ
  </div>
  <div style="float:left; width:60%; background:aqua;">
    float: left の要素<br>
  </div>
</div>
<p>横並びってどないやねん</p>
<p>横並びってどないやねん</p>
<p>横並びってどないやねん</p>
<p>横並びってどないやねん</p>
回り込み解除された表示
回り込み解除された表示

float解除方法のまとめ(clearfixなし)

ということで、floatで横並びレイアウトされた要素をclearfixなしで回り込み解除させる方法はこの4種類です。

  1. 横並びレイアウト最後の要素の次の要素にclear:bothを指定(空要素で親要素のお尻を作って親要素範囲を確定。親要素の中で回り込みを解除し完結させる)
  2. 横並びレイアウトを包む親要素の次の要素にclear:bothを指定(次に来る要素で回り込みを解除。親要素は描画されないため背景色などは反映されない)
  3. 横並びレイアウトを包む親要素に子要素以上のheightを指定(height:0だった親要素に範囲を与えることでfloat子要素をはみ出させない)
  4. 横並びレイアウトの親要素にブロック整形コンテキストとしてfloatではないものを指定(visible以外のoverflow、position:absolute、display:table-cell など)

HTMLとCSSのセットは文書でありレイアウトでもあるから、どこに何を設定するか混乱しますね〜。

困りごとが出てきた

上の解決策で問題ない気もしますが、次のような悩みも出てきます。

特に、回り込み解除のための空白要素を置くのは一番シンプルな解決策に見えて、後で別の人が触る時に余計なものだろうと考えて消してしまってレイアウトが崩壊することが多々ありました。困ったね。

clearfixの登場

高さや次に来る要素が固定でない横並びレイアウトの回り込み解除のこのような困りごとをCSSのクラス付与だけで何とかするために登場したのがclearfixです。

こちらは2006年の記事です。IE5〜IE7で対応するためのコードが紹介されています。
この頃からすでに散々苦しんできた雰囲気が伝わってきます。
「clearfix」のIE 7対策:その2 | コリス

こちらは2009年の記事。
[CSS]floatを解除する「clearfix」のIE6/7に対応した改良版 | コリス

おそらくこれが最新になる、2016年の記事。
clearfixの最新版 -フロート関連やマージン相殺の不具合を解決するモダンブラウザ用clearfix | コリス

2017年ごろからFlexboxがどんどん使えるようになっていった記憶があります。

clearfixを使ってみる

実際にclearfixを使用してみます。

CSS

.clearfix:after {
  content:" ";
  display:block;
  clear:both;
}

HTML

<div style="width:400px;" class="clearfix">
  <div style="float:left; width:40%; background:pink;">
    float: left の要素<br>ああああああ<br>あああ<br>ああああ
  </div>
  <div style="float:left; width:60%; background:aqua;">
    float: left の要素<br>
  </div>
</div>
<p>横並びってどないやねん</p>
<p>横並びってどないやねん</p>
<p>横並びってどないやねん</p>
<p>横並びってどないやねん</p>

横並びレイアウトを包む親要素にclearfixクラスを指定すると、要素に高さの指定がなくても回り込みが解除されスッキリします。

after擬似要素を使って「回り込み解除を指定した横100%のブロック要素」を作り、親要素内部の一番最後に配置することで、親要素の範囲を固定する、というやり方になっています。(この記事の回り込み解除方法で最初に紹介したものと同じ動き)

clearfixを使いafter擬似要素で回り込み解除
after擬似要素で回り込み解除する

昔のclearfixだとbefore要素も置いてたんですが、そうしないと一部のブラウザで上のmarginも吹っ飛んでいました。
詳しくは上で紹介したリンク先の説明をご覧ください。

とにかくclearfixがないとfloatでのレイアウトは厄介なものでした。

あの頃にあったzoom:1って何だったんだろう

2011年に発表されたmicro clearfixを現在も使用しているサイトがたまにあります。
10年使われてるってターゲットブラウザ広すぎてヤバいな。

/* For modern browsers */
.cf:before,
.cf:after {
  content:" ";
  display:table;
}
    
.cf:after {
  clear:both;
}
    
/* For IE 6/7 (trigger hasLayout) */
.cf {
  zoom:1;
}

ここにある「zoom:1」というプロパティ、昔のIEを触ったことがない方だと全く見たことがないのではないでしょうか。

もともとはtransform:scale()と同じ、要素の拡大・縮小を行うプロパティでした。非標準です。

実際にどんな感じかはMDNのサンプルを見てみてください。Chrome、Safari、Edgeでも反映されます。
zoom – CSS: カスケーディングスタイルシート – MDN Web Docs

しかしここのzoomは拡大率のために指定されているのではありません。
拡大率が1で無意味に見えますが、無意味でもなく……。

hasLayout

すでに紹介したこれらの記事にも出てきますが、IE独自のhasLayoutという値をtrueにするために設定されたプロパティでした。
[CSS]floatを解除する「clearfix」のIE6/7に対応した改良版 | コリス
clearfixの最新版 -フロート関連やマージン相殺の不具合を解決するモダンブラウザ用clearfix | コリス

hasLayoutはIE8からは存在しない値です。

2011年時点でブラウザの主流はIE9だったのですが、業務用パソコンでまだまだIE6/7が生きていたので、それらIEのhasLayout指定のためによく使われていました。2001年に公開されたIE6のお葬式が行われたのが2010年3月です。察して。

hasLayoutについて詳しくは2007年のこちらの記事を読むと良いかも。
IEでのCSSのバグを回避するhasLayout | コリス

探してみると最近の記事もいくつかありました。

hasLayoutとzoom: 1 – Qiita

今さらだけど、IE6対策中心のCSSメモ | HAPPEN
↑ここが一番詳しい。

読んでいると昔を思い出して鳩尾のあたりが調子悪くなってきます。

IE6/7はとにかくバグが多かったんですが、特にfloat要素が溢れるとか中身が消えることがよくあり、それを回避するためにhasLayout=trueにしていました。
hasLayout=trueの時に起きるバグもあるので、なんかもうどうにかしてくれというあの頃の気持ちがね! 蘇るね!

IEでの見た目を揃えるのがあんまりにもあんまりだからIETesterとかもあったね! よくわからんバグのよくわからん回避技とか……ブラウザごとにCSS書いたりとか……苦しみがたくさん……あったね……。

古の知恵もたまに覗いてみてください

CSSは新しくて便利な要素がどんどん増えてますが、少し古い案件を扱う時のためにも、ちょっと昔の話題も調べてみると面白いですぞ。

思い出そうとするだけでなんかすっごく胃が痛いけれど……。

IEはねぇ…うふ…ふふふ……ハハッ

IE11のサポート終了は2022年6月です。早く苦しみと悪夢から解き放たれたい……。