overflow は、要素の中身が枠からはみ出したときの扱いを決めるプロパティです。はみ出しの処理という本来の役目のほかに、「中の float を親要素が囲むようになる」という副作用を目当てに、広く使われてきました。ただし古い Internet Explorer、特に IE6 では、この副作用が同じようには働きませんでした。

overflow の値

  • visible (初期値): はみ出した部分も、そのまま表示する
  • hidden: はみ出した部分を切り取る。スクロールバーは出ないが、JavaScript からはスクロールできる
  • scroll: 切り取ったうえで、常にスクロールできるようにする (スクロールバーの見え方は OS やブラウザーの設定による)
  • auto: はみ出したときだけ、スクロールできるようにする
  • clip: 切り取る。hidden と違い、JavaScript からもスクロールできない

overflow-x と overflow-y で、横と縦を別に指定することもできます。ただし、片方を hidden・scroll・auto のどれかにすると、もう片方の visible は auto として扱われます。「縦は切り取り、横ははみ出させる」という組み合わせは作れないので注意してください。

.scroll-area {
  max-height: 300px;
  overflow-y: auto; /* 300px を超えたら縦にスクロールさせる */
}

overflow で float を囲める理由

float した子要素は通常の流れから外れるため、親要素の高さの計算に含まれません。画像を float させて横に文章を置くと、画像のほうが高い場合、画像が親要素の下にはみ出します。

<div class="media">
  <img class="media-image" src="photo.jpg" alt="" width="120" height="90">
  <p>説明の文章</p>
</div>
.media-image {
  float: left;
  margin-right: 16px;
}

.media {
  overflow: hidden; /* 画像が文章より高くても、親要素が画像を囲む */
}

overflow を visible と clip 以外の値にすると、その要素は新しい「ブロック整形文脈」(Block Formatting Context、BFC) を作ります。BFC は、中のレイアウトをその中だけで完結させる領域で、次の性質があります。

  • 中の float の高さも含めて、自分の高さを決める
  • 外にある float と重ならず、その横に並ぶ
  • 子要素のマージンが、自分のマージンと相殺されない

1 つ目の性質のおかげで、overflow: hidden を指定するだけで float を囲めるわけです。overflow: clip は BFC を作らないので、この目的には使えません。

古い IE で起きていたこと

IE7 までは、BFC の代わりに hasLayout という独自の内部状態で、要素の配置を決めていました。IE7 では overflow を visible 以外にすると hasLayout が true になりましたが、IE6 ではなりませんでした。そのため IE6 では、overflow: hidden だけでは float を囲めず、width や height を指定するか、zoom: 1 を加えて hasLayout を true にする必要がありました。

.media {
  overflow: hidden;
  zoom: 1; /* IE6 向け: hasLayout を true にする */
}

hasLayout については、zoom: 1 の落とし穴 ── hasLayout と番号付きリスト でも紹介しています。

IE6・IE7 には、ほかにも overflow にからむ不具合がありました。

  • overflow: hidden や auto の親要素の中に position: relative の子要素があると、子要素が切り取られずにはみ出す。親要素にも position: relative を付けると直った
  • IE6 では、height を指定しても、中身に合わせて要素が広がる。高さ 1px の線を作ろうとしても文字の高さまで広がってしまうので、overflow: hidden を付けて抑えた

今は display: flow-root を使う

今のブラウザーでは、IE 向けの指定は要りません。そのうえで、float を囲む目的で overflow: hidden を使うのも、今はおすすめしません。はみ出したものを切り取るという本来の働きがあるため、次のような副作用が出るからです。

  • box-shadow の影や、ドロップダウンメニュー、ツールチップなど、枠の外に出したいものまで切れる
  • 中にある position: sticky の要素が、ページのスクロールに合わせて止まらなくなる (overflow: hidden の要素がスクロールの基準になるため)

BFC だけを作りたいときは、display: flow-root を使います。名前のとおり、新しい整形文脈の根 (root) になるための値で、切り取りなどの副作用はありません。

.media {
  display: flow-root; /* 中の float を囲む。はみ出したものは切り取らない */
}

そもそも、横並びのレイアウトのために float を使う場面は少なくなりました。画像と文章を横に並べるだけなら、Flexbox や Grid のほうが素直に書けます。Flexbox や Grid のコンテナーは、それ自体が中の要素を囲むので、回り込みの解除も要りません。float は、文章を画像の周りに回り込ませるという本来の用途で使うとよいでしょう。

まとめ

  • overflow は、はみ出した中身を表示するか、切り取るか、スクロールさせるかを決める
  • visible と clip 以外の値にするとブロック整形文脈 (BFC) ができ、中の float を囲む
  • IE6 ではこの効果が出ず、width・height や zoom: 1 で hasLayout を true にしていた
  • 今は、float を囲むだけなら display: flow-root を使う。overflow: hidden には切り取りの副作用がある

参考