系列文章
- [ 面试系列 ] - 一:你是如何理解 HTML 语义化的?
- [ 面试系列 ] - 二:meta viewport 是做什么用的,怎么写?
- [ 面试系列 ] - 三:H5 是什么?
- [ 面试系列 ] - 四:两种盒模型分别说一下
- [ 面试系列 ] - 五:如何垂直居中?
什么是 BFC?
BFC(Block Formatting Context),即块格式化上下文,在前端开发中也是一个老生常谈的问题了,我们首先来看看 MDN 对其的解释:
块格式化上下文(Block Formatting Context,BFC) 是 Web 页面的可视化 CSS 渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。

(小声哔哔:听听,这是人说的话吗?)
上翻译机:事实上,BFC 的目的是形成一个相对于外界完全独立的空间,让内部的子元素不会影响到外部的元素。
为什么会出现 BFC?
上面已经解释了什么是 BFC,它的作用是什么,那么为什么会出现 BFC 呢?
相信做过前端开发的同学都遇到过进行页面布局的时候,应该都有遇到过以下情况:
- 这个元素高度怎么没了?
- 这两栏布局怎么没法自适应?
- 这两个元素的间距怎么有点奇怪的样子?
- ......
为什么会出现上面的情况呢?
究其原因就是因为元素之间相互的影响,导致了预料之外的情况。
那么结合 BFC 的特性,答案就很明了了:BFC 是为了解决元素之间相互影响的问题的。所以 BFC 的功能是形成一个相对于外界独立的空间,让内部的子元素不会影响到外部元素。
怎么创建 BFC?
我们知道了 BFC 是为了解决什么问题而出现的,那么怎么创建一个 BFC 呢?
当然,可以参考 MDN,但这实在是太难记了,通常我们只需要记住下面六种情况即可:
- float 不为 none
- position 为 absolute 或 fixed
- overflow 不为 visible
- display 为 inline-block 或 table-cell
- display 为 flex/inline-flex 的直接子元素
- display 为 grid/inline-grid 的直接子元素
应用场景
父元素高度坍塌
我们知道,如果一个父元素里的子元素一旦设置了浮动,那么父元素就无法检测到子元素的高度,那么如果父元素里的所有子元素都浮动起来的话,父元素的高度就无法被子元素撑开,会塌陷下去,这个现象称为父元素高度塌陷。
我们来看看代码:
<style>
.futher {
padding: 10px;
background-color: deepskyblue;
}
.child {
width: 20px;
height: 20px;
background-color: deeppink;
float: left;
}
</style>
<body>
<div class="futher">
<div class="child"></div>
</div>
</body>
效果如下:

显然,这并不是我们希望见到的情况,而通过 BFC 则能很好的解决这个问题:
我们给父元素添加 overflow: hidden,效果如下:

事实上,既然我们已经知道了父元素为什么塌陷,对于这个问题自然会有其他的解决方案:
比如我们在子元素后面添加一个 div,用于清除浮动:
<style>
.futher {
padding: 10px;
background-color: deepskyblue;
}
.child {
width: 20px;
height: 20px;
background-color: deeppink;
float: left;
}
.clear-both {
clear: both;
}
</style>
<body>
<div class="futher">
<div class="child"></div>
<div class="clear-both"></div>
</div>
</body>
当然,更好的写法可以利用伪元素:
.child::after {
clear: both;
}
自适应布局
在日常的开发中,两栏自适应布局是非常常见的,通常一遍固定宽度,而另一边则随窗口自适应:

对于上图,我们的实现通常是让左侧浮动起来,利用块会自动占满整个宽度的特性,实现右侧自适应。不过如果右侧高度大于了左侧,则会出现如下的尴尬情况:

这个时候,利用 BFC,也能很好的解决问题:

同上一个场景,我们知道了出现问题地原因,那么通过别的方案,自然也能解决问题,比如设定一个安全的 margin-left:
:root {
--safe-margin: 100px;
}
.left {
width: var(--safe-margin);
height: 50vh;
background-color: deeppink;
float: left;
}
.right {
margin-left: var(--safe-margin);
height: 100vh;
background-color: deepskyblue;
}
外边距重叠(边界折叠)
还记得上上集提到的边界折叠吗?
那里主要讲了父元素和子元素的重叠,这里讲一下兄弟之间的重叠。
.one {
height: 100px;
margin-bottom: 100px;
background-color: deepskyblue;
}
.two {
height: 100px;
margin-top: 100px;
background-color: deeppink;
}
知道边界折叠现象的我们应该清楚,这里两个元素之间的 margin 并不是 (100 + 100 = 200)px,而是取其中的大者(两者一样大)的 100px:

对于这个问题,我们同样可以通过 BFC 来解决:
<style>
* {
margin: 0;
padding: 0;
}
.one {
height: 100px;
margin-bottom: 100px;
background-color: deepskyblue;
}
.twp-wrap {
overflow: hidden;
}
.two {
height: 100px;
margin-top: 100px;
background-color: deeppink;
}
</style>
<body>
<div class="one"></div>
<div class="twp-wrap">
<div class="two"></div>
</div>
</body>
