浮动造成的"高度塌陷"几乎是每个前端的必经之坑。这篇文章从原理到实践,带你彻底搞懂 BFC 和清除浮动的各种姿势。

0 阅读6分钟

前言

还记得我刚学前端的时候,写了个三栏布局,左边右边都浮动了,结果父元素高度变成 0,下面的内容直接顶上来了,整个页面乱成一团。

当时我的解决方案?百度一下,复制一段 .clearfix 代码,搞定收工。但说实话,我根本不知道这段代码为啥能生效,也不知道 BFC 是个啥东西。

后来踩的坑多了,才明白:不理解 BFC,就永远搞不懂浮动清除的本质。今天把我这些年对 BFC 和浮动清除的理解分享出来,希望能帮你少走点弯路。


一、BFC 到底是个啥?

1.1 一句话解释

BFC(Block Formatting Context)就是一个独立的渲染区域,里面的元素怎么布局,跟外面没关系;外面的元素怎么布局,也影响不到里面。

就像给元素套了一层"结界",结界内外互不干扰。

1.2 BFC 的核心规则

理解这几条规则,BFC 就掌握了一半:

  1. 内部的盒子垂直排列 —— 块级元素嘛,从上到下排
  2. 相邻元素的垂直外边距会折叠 —— 这个坑很多人踩过
  3. BFC 区域不会与浮动元素重叠 —— 两栏自适应布局就靠这个
  4. 计算 BFC 高度时,浮动元素也参与计算 —— 清除浮动的核心原理!
  5. 内外互不影响 —— 结界的本质

1.3 怎么触发 BFC?

满足下面任意一条,就能创建 BFC:

属性副作用
floatleft / right元素脱离文档流
positionabsolute / fixed元素脱离文档流
displayinline-blockflexgrid改变盒类型
overflowhiddenautoscroll可能裁剪内容或出滚动条
display: flow-root无副作用,专门创建 BFC

推荐:现代浏览器直接用 display: flow-root,干净无副作用。需要兼容 IE?用 overflow: hidden 或 clearfix。


二、浮动带来的麻烦:高度塌陷

2.1 浮动是什么?

元素设置 float: left/right 后:

  1. 脱离正常文档流,向指定方向飘
  2. 碰到包含块边缘或其他浮动元素就停下来
  3. 后面的块级元素会无视它,占据它的位置
  4. 行内元素即文字会环绕它

2.2 高度塌陷是怎么发生的?

<div class="parent">
  <div class="float-left" style="float: left; width: 200px; height: 100px; background: red;"></div>
  <div class="float-right" style="float: right; width: 200px; height: 100px; background: blue;"></div>
</div>
<div class="next">我是下面的内容</div>

你会发现:

  • .parent 的高度是 0(或者只有边框/内边距的高度)
  • .next 直接顶上来了,跟浮动元素重叠

原因:浮动元素脱离了文档流,父元素感知不到它们的高度,所以高度塌陷了。

这就是浮动最经典的副作用,也是面试常问的问题。


三、清除浮动的 N 种方案

清除浮动本质上就两条路:

  1. 让某个元素 clear 掉浮动 —— 撑开父元素
  2. 让父元素变成 BFC —— 自动包裹浮动子元素

方案一:clear 属性(经典方案)

clear 的作用是:要求元素的某一边不能有浮动元素。如果有,就移到浮动元素的下方。

1.1 空标签法(不推荐)

<div class="parent">
  <div class="float-left"></div>
  <div class="float-right"></div>
  <div style="clear: both;"></div>  <!-- 专门用来清除浮动 -->
</div>
  • 优点:简单,兼容性好
  • 缺点:增加无意义标签,违反语义化

1.2 伪元素 clearfix(最常用)

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

/* 兼容 IE6/7 */
.clearfix {
  *zoom: 1;
}

原理:::after 在父元素末尾生成一个不可见的块级元素,设置 clear: both,从而撑开父元素高度。

  • 优点:无额外标签,可复用,兼容性好
  • 缺点:需要记住类名,老项目要加 zoom

这是目前最经典、使用最广泛的方案。维护老项目时,看到 .clearfix 就放心用吧。

方案二:触发父元素 BFC

根据 BFC 规则第 4 条:计算 BFC 高度时,浮动元素也参与计算

所以只要让父元素变成 BFC,它就会自动包裹浮动子元素,高度不再塌陷。

2.1 overflow: hidden(简单粗暴)

.parent {
  overflow: hidden;  /* 或 auto */
}
  • 优点:代码极简,兼容性好
  • 缺点:会裁剪溢出内容(比如绝对定位的子元素、阴影等),auto 可能产生不必要的滚动条

真实踩坑:我曾经为了清除浮动,给父元素加了 overflow: hidden,结果里面的下拉菜单被裁掉了,找了半天才发现是这个原因 😅

2.2 display: flow-root(现代最佳)

.parent {
  display: flow-root;
}
  • 优点:专门为了创建 BFC 而生,并且零副作用 —— 不裁剪内容、不产生滚动条、不改变盒模型
  • 缺点:IE 不支持(但谁还管 IE 呢)

如果项目不需要兼容 IE,这是目前最优雅的方案。

2.3 其他触发方式(不推荐)

/* 这些也能创建 BFC,但有副作用 */
.parent { float: left; }        /* 父元素也脱离文档流 */
.parent { position: absolute; } /* 父元素脱离文档流 */
.parent { display: inline-block; } /* 改变盒类型,可能失去块级特性 */

这些方式虽然能创建 BFC,但会改变父元素的布局行为,除非有特殊需求,否则别用。

方案三:直接不用浮动(终极方案)

如果布局场景本身不需要浮动,只是想让元素横向排列,直接用 FlexboxGrid

.parent {
  display: flex;
  /* 或 display: grid; */
}
  • 没有浮动,就没有清除的烦恼
  • 布局能力远超浮动
  • 代码更简洁

除非要兼容 IE9 及以下,否则新项目无脑用 Flexbox/Grid。


四、方案对比总结

方案原理是否加标签副作用兼容性推荐度
空标签 clear:bothclear 属性✅ 加标签全兼容
伪元素 clearfixclear 属性❌ 伪元素全兼容(IE需zoom)
overflow: hidden触发 BFC可能裁剪内容IE6+
display: flow-root触发 BFC现代浏览器最高
父元素 float/position触发 BFC父元素脱离文档流全兼容极低
Flexbox/Grid现代布局IE10+最高

五、实战建议

5.1 维护老项目

如果项目里已经有 .clearfix 类,继续用就行,别折腾。稳定大于一切。

5.2 新项目不兼容 IE

无脑用 display: flow-root,语义明确,零副作用。

/* 推荐 */
.parent {
  display: flow-root;
}

5.3 重写布局

如果还在用浮动做多列布局,尽快升级到 Flexbox 或 Grid。不仅没有清除浮动的烦恼,代码也更简洁易懂。

5.4 注意 overflow 的坑

很多人为了清除浮动无脑加 overflow: hidden,结果把弹出层、下拉菜单、阴影裁剪掉了。排查起来很痛苦,切记慎用。

5.5 一句话总结

清除浮动就两条路:

  1. clear 属性 —— 让元素走到浮动下方撑开父级
  2. 触发 BFC —— 让父级自己识别浮动高度

理解了这个本质,不管面试官怎么问,你都能从容应对。


写在最后

BFC 和浮动清除是 CSS 布局的底层知识。掌握了它们,你不仅能自信应对高度塌陷问题,更能深刻理解 CSS 的渲染机制。

虽然现在 Flexbox 和 Grid 已经能覆盖大部分布局需求,但理解 BFC 依然很重要 —— 毕竟面试要考,维护老项目也要用。

有问题评论区见,觉得有帮助点个赞