最近在学习 CSS 的时候,遇到了一个很经典的"问题",就是父元素的高度塌陷。相信很多jym都踩过这个坑。代码很简单,就像下面这样:
html
<!DOCTYPE html>
<html lang="en">
<head>
<title>BFC 探秘</title>
<style>
.container{
background-color: aqua; /* 一个浅蓝色的父容器 */
}
.box{
margin: 100px;
width: 100px;
height: 100px;
background-color: red; /* 三个红色的小方块 */
float: left; /* 关键在这里,我们让它们浮动了 */
}
</style>
</head>
<body>
<div class="container">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
</body>
</html>

父容器去哪了?
当我把这段代码在浏览器里打开时,我惊奇地发现,那个浅蓝色的父容器 .container
几乎看不见了!里面的三个红色小方块倒是好好地排列着,但它们好像"脱离"了父容器的包裹。
这就是典型的 "高度塌陷" 问题。
为什么会这样呢?因为子元素 .box
设置了 float: left;
,变成了浮动元素。元素一旦浮动,就像气球一样,脱离了正常的文档流,不再占据父容器的高度。父容器 .container
里面没有其他非浮动的元素来撑开它的高度,所以它的高度就"塌陷"为 0 了。
救星登场:BFC (块级格式化上下文)
为了解决这个问题,我查阅了很多资料,发现了一个神奇的东西------BFC(Block Formatting Context) ,中文名叫"块级格式化上下文"。
听起来很玄乎,但我们可以把它理解成一个独立的、与外界隔离的"小房间" 。在这个"小房间"里,元素的布局有它自己的一套规则,不会影响到外面的世界,外面的布局也影响不到它。
BFC 有很多特性,其中最关键的一条就是:计算 BFC 的高度时,浮动元素也参与计算。
这不就正好解决了我们的问题吗!只要我们想办法让父容器 .container
变成一个 BFC,它在计算自身高度时就会把浮动的子元素 .box
也算进去,高度塌陷的问题自然就解决了。
那么我们该 如何触发 BFC?
让一个元素变成 BFC 的方法有很多,这里列举几个常用的:
overflow: hidden;
(或者auto
,scroll
)display: inline-block;
display: flow-root;
(这是最推荐的、专门用来创建 BFC 的属性,但有兼容性问题)position: absolute;
或position: fixed;
- 根元素
<html>
本身就是一个 BFC。
对于我们上面的例子,最简单、副作用最小的修改方法就是给 .container
添加 overflow: hidden
:
css
.container {
background-color: aqua;
overflow: hidden; /* 就是加了这一行! */
}
加上之后再看效果,我们发现浅蓝色的父容器回来了,完美地包裹住了三个红色的小方块。问题解决!

除了解决高度塌陷,BFC 还能用来防止外边距重叠。
外边距重叠是指在正常的文档流中,相邻的两个块级元素的垂直外边距(margin-top
和 margin-bottom
)会发生合并,合并后的外边距高度等于两个发生合并的外边距中较高的那个值。
听起来有点绕?我们直接看代码,秒懂!
假设我们有两个兄弟 div
,一个上边距 20px,一个下边距 30px。
html
<style>
body {
background-color: #f0f0f0; /* 加个背景色方便观察 */
}
.box {
width: 100px;
height: 100px;
background-color: skyblue;
}
.box1 {
margin-bottom: 30px; /* box1 的下外边距是 30px */
}
.box2 {
margin-top: 50px; /* box2 的上外边距是 50px */
background-color: tomato;
}
</style>
<div class="box box1">Box 1</div>
<div class="box box2">Box 2</div>
预期效果 :我们可能会认为,Box 1
和 Box 2
之间的距离应该是 30px + 50px = 80px
。
实际效果 :但实际上,它们之间的距离只有 50px
。因为 box1
的 margin-bottom
和 box2
的 margin-top
发生了重叠,浏览器会取其中较大的值(50px)作为它们之间的最终间距。
这就是最常见的外边距重叠。

BFC 如何防止外边距重叠?
还记得我们把 BFC 比作一个"独立的、与外界隔离的小房间"吗?
BFC 的一个重要特性就是:BFC 内部的元素外边距不会与外部的元素发生重叠。
利用这个特性,我们就可以巧妙地阻止外边距重叠的发生。
解决方案:
我们只需要在两个兄弟元素之间,再包裹一层元素,并让这个包裹层触发 BFC。
看修改后的代码:
html
<style>
body {
background-color: #f0f0f0;
}
.box {
width: 100px;
height: 100px;
background-color: skyblue;
}
.box1 {
margin-bottom: 30px;
}
.box2 {
margin-top: 50px;
background-color: tomato;
}
/* 新增一个 BFC 容器 */
.bfc-wrapper {
overflow: hidden; /* 触发 BFC 最简单的方式 */
}
</style>
<div class="box box1">Box 1</div>
<!-- 用一个 BFC 容器把第二个 box 包起来 -->
<div class="bfc-wrapper">
<div class="box box2">Box 2</div>
</div>
发生了什么变化?
- 我们创建了一个新的
div
,类名为.bfc-wrapper
。 - 我们给这个 wrapper 添加了
overflow: hidden;
,这样它就变成了一个 BFC。 - 我们把
box 2
放进了这个 BFC 容器里。
现在,box 1 的 margin-bottom
是和 .bfc-wrapper 的 margin-top
(默认为0) 去尝试重叠。
而 box 2 的 margin-top
因为被关在了 BFC 这个"独立小房间"里,所以它只能和"小房间"内部的元素发生关系,无法"穿透"出来影响到外面的 box 1。
最后 box 1 和 box 2 之间的距离现在是 30px + 50px = 80px
。外边距重叠的问题被成功解决了!
总结
今天我们从一个简单的"高度塌陷"问题出发,学习了 BFC 的概念和用法,知道了如何通过 overflow: hidden
等方式来创建 BFC 并解决问题。通过这些简单的例子,我们可以看到 BFC 的强大之处。它就像一个结界,将内部元素的布局规则与外部隔离开来。
当你遇到一些看似"诡异"的布局问题,比如浮动元素导致父元素高度塌陷,或者垂直外边距没有按照预期工作时,不妨想一想,是不是可以通过触发 BFC 来解决。