CSS Handbook · 布局

第六章 / 6.5 浮动与 BFC

第六章 · 6.5 节

浮动与 BFC


在 Flexbox 与 Grid 出现之前,float 曾是唯一能实现"多栏并排"的手段,也因此留下了一整套配套的 hack 技巧。今天我们很少再用 float 搭建整体布局,但它引出的 BFC(块级格式化上下文)概念,至今仍是排查布局异常的重要工具。

float 的原始用途

float 最初是为"文字环绕图片"设计的:设置了 float 的元素会脱离正常文档流,向左或向右靠拢,后面的行内内容则环绕在它周围。

img.thumb {
  float: left;
  margin-right: 12px;
}
效果预览:文字环绕
图
这是一段环绕在浮动图片右侧的文字,行文会自动避开浮动元素占据的区域,直到超出浮动元素的高度后才会恢复满宽排列,这正是 float 最初被设计用来解决的排版问题。

高度塌陷问题

float 元素脱离了文档流,一个尴尬的后果是:如果父元素只包含浮动的子元素,父元素会"看不到"它们的高度,表现为高度塌陷为 0。

/* 父元素高度会塌陷 */
.row {
  border: 1px solid #c9cabf;
}
.row .col {
  float: left;
  width: 50%;
}

经典的补救写法是 clearfix,本质是用一个伪元素强制"清除浮动":

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

什么是 BFC

BFC(Block Formatting Context,块级格式化上下文)是页面中一块"独立的渲染区域"——BFC 内部的盒子如何布局,不会影响到外部;反过来,外部元素也无法影响 BFC 内部的布局。它可以理解为一个隔离的排版容器。

clearfix 之所以有效,本质是给父元素触发了 BFC——BFC 会包裹住内部所有浮动元素的高度,不再塌陷。这也是为什么现代写法更推荐直接触发 BFC,而不是额外插入清除用的伪元素。

如何创建 BFC

触发方式说明
overflow: hidden / auto最常见的写法,但会连带裁剪溢出内容
display: flow-root现代首选:专为触发 BFC 设计,无副作用
display: flex / grid / inline-block切换显示类型的同时,也会创建 BFC
position: absolute / fixed脱离文档流的同时创建 BFC
/* 现代 clearfix:无副作用,语义清晰 */
.row {
  display: flow-root;
}
推荐只要目的是"包裹浮动子元素的高度",优先使用 display: flow-root,它是专门为此设计的属性值,不会像 overflow: hidden 那样意外裁掉子元素的阴影或下拉菜单。

BFC 的实际用途

  • 包裹浮动高度:如上所述,解决父元素高度塌陷。
  • 阻止外边距合并:两个相邻块级元素的垂直 margin 默认会合并取较大值,把其中一个包裹进新的 BFC 可以阻止这种合并。
  • 避免文字环绕浮动元素:给紧邻浮动元素的普通块级盒子触发 BFC,它会形成独立区域,不会被浮动元素挤压环绕,从而实现"两栏都不环绕文字"的整齐布局。

今天还需要 float 吗

在整体页面布局层面,float 已经被 Flexbox 与 Grid 完全取代——它们更直观、无需 clearfix、也没有高度塌陷的历史包袱。但 float 最初设计的场景——"文字环绕图片/首字下沉"——至今仍是它唯一无可替代的用途,Flexbox 和 Grid 都无法做到"内容围绕一个矩形环绕排列"的效果。

Chapter 6 · Section 6.5

Floats and BFC


Before Flexbox and Grid, float was the only way to achieve "multi-column side-by-side" layouts, and it left behind a whole set of companion hacks. Today we rarely use float for whole-page layouts, but the BFC (block formatting context) concept it gave rise to remains an important tool for debugging layout anomalies.

The Original Purpose of float

float was originally designed for "text wrapping around images": an element with float leaves the normal document flow and moves to the left or right, while the inline content that follows wraps around it.

img.thumb {
  float: left;
  margin-right: 12px;
}
Preview: text wrapping
Img
This is text wrapping around the right side of a floated image. The lines automatically avoid the area occupied by the floated element, and only return to full-width layout after passing the floated element's height — exactly the typesetting problem float was originally designed to solve.

The Height Collapse Problem

Because floated elements leave the document flow, one awkward consequence is: if a parent contains only floated children, it "cannot see" their height, and its height collapses to 0.

/* the parent's height collapses */
.row {
  border: 1px solid #c9cabf;
}
.row .col {
  float: left;
  width: 50%;
}

The classic fix is clearfix, which essentially forces a pseudo-element to "clear the float":

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

What Is a BFC

A BFC (Block Formatting Context) is an "independent rendering region" on the page — how boxes inside the BFC are laid out does not affect the outside; conversely, external elements cannot affect the layout inside a BFC either. Think of it as an isolated layout container.

clearfix works because it essentially triggers a BFC on the parent — the BFC wraps the height of all floated children inside it, so it no longer collapses. That is also why modern approaches prefer triggering a BFC directly instead of inserting an extra clearing pseudo-element.

How to Create a BFC

TriggerDescription
overflow: hidden / autoThe most common approach, but it also clips overflowing content
display: flow-rootThe modern first choice: designed specifically to trigger a BFC, with no side effects
display: flex / grid / inline-blockSwitching the display type also creates a BFC
position: absolute / fixedCreates a BFC while leaving the document flow
/* modern clearfix: no side effects, clear semantics */
.row {
  display: flow-root;
}
RecommendedAs long as the goal is "wrapping the height of floated children", prefer display: flow-root — it is the value designed for exactly this, and unlike overflow: hidden it will not accidentally clip a child's shadow or dropdown menu.

Practical Uses of a BFC

  • Wrapping floated height: as described above, solving the parent's height collapse.
  • Preventing margin collapse: the vertical margins of two adjacent block-level elements merge to the larger value by default; wrapping one of them in a new BFC stops the merge.
  • Avoiding text wrapping around floats: trigger a BFC on an ordinary block-level box next to a floated element; it becomes an independent region that is not squeezed or wrapped by the float, giving a clean "two-column, no wrapping" layout.

Do We Still Need float Today?

At the level of whole-page layout, float has been completely replaced by Flexbox and Grid — they are more intuitive, need no clearfix, and carry none of the height-collapse baggage. But the scenario float was originally designed for — "text wrapping around images / drop caps" — remains its only irreplaceable use to this day: neither Flexbox nor Grid can make "content flow around a rectangle" work.