BFC 与格式化上下文
什么是 BFC
BFC(Block Formatting Context,块级格式化上下文)是 CSS 视觉格式化模型中的一种独立布局环境。可以把它理解为页面中的一块“隔离布局区域”:
- BFC 内部的块级盒子按照正常文档流在垂直方向排列。
- BFC 内部的布局通常不会影响外部元素,外部浮动也不会侵入该区域。
- BFC 会包含其内部的浮动元素,并参与高度计算。
“互不影响”是一种便于理解的概括,并非完全隔离。元素的继承、尺寸约束以及层叠关系等仍然可能跨越 BFC 边界。
BFC 的布局规则
-
块级盒子垂直排列
同一 BFC 中,块级盒子从上到下依次排列。
-
相邻块的外边距可能折叠
同一 BFC 中,相邻块级元素的垂直
margin可能发生折叠;不同 BFC 之间不会发生垂直外边距折叠。 -
BFC 不与浮动盒子重叠
BFC 会避开同级浮动元素,其可用宽度会根据浮动元素占用的空间进行收缩。
-
BFC 会包含内部浮动元素
计算 BFC 高度时,其内部的浮动元素也会被计算在内,因此可用于解决父元素高度塌陷。
触发 BFC 的常见条件
以下情况会创建新的 BFC:
- 根元素
<html>。 float的值不是none。position为absolute或fixed。display为inline-block。display为flow-root。display为table-cell、table-caption等表格相关值。overflow的值不是visible或clip,例如hidden、auto、scroll。display为flex或inline-flex的元素,其直接子元素会建立 BFC。display为grid或inline-grid的元素,其直接子元素会建立 BFC。contain包含layout、content或paint。- 多列容器,例如设置了
column-count或column-width的元素。
💡 如果只是为了显式创建 BFC,优先使用
display: flow-root。它能清晰表达布局意图,也不会像overflow: hidden一样意外裁剪溢出内容。
BFC 的典型应用
1. 清除浮动,避免父元素高度塌陷
子元素浮动后会脱离普通文档流,父元素可能无法被其撑开。让父元素创建 BFC 后,计算高度时会包含浮动子元素。
.parent {
display: flow-root;
}
.child {
float: left;
}
传统方案常使用 overflow: hidden,但它可能裁剪阴影、下拉菜单等溢出内容,因此通常更推荐 flow-root。
2. 避免父子元素的垂直 margin 折叠
父元素与第一个或最后一个普通流子元素之间,垂直 margin 可能发生折叠。让父元素建立 BFC 可以阻止这种跨边界折叠。
.parent {
display: flow-root;
}
.child {
margin-top: 20px;
}
不过,如果只是需要父子间距,使用父元素的 padding 或 gap 往往语义更明确。
3. 避免元素被浮动元素覆盖
普通块级元素的边框盒可能延伸到浮动元素下方,而其文本内容会环绕浮动元素。让该元素创建 BFC 后,它会避开浮动元素,形成常见的两栏布局。
.aside {
float: left;
width: 200px;
}
.main {
display: flow-root;
}
现代项目通常优先使用 Flexbox 或 Grid 实现两栏布局;BFC 更适合处理已有浮动布局或理解浏览器行为。
容易混淆的概念
BFC 与包含块(Containing Block)
- BFC 决定盒子如何参与布局,以及浮动、外边距折叠等行为。
- 包含块 是计算元素尺寸和位置的参照区域,例如绝对定位元素会寻找其定位包含块。
两者可能由同一个元素产生,但不是同一概念。
BFC 与层叠上下文(Stacking Context)
- BFC 主要处理布局。
- 层叠上下文 主要处理元素在 z 轴上的覆盖顺序。
创建 BFC 不一定创建层叠上下文,创建层叠上下文也不一定创建 BFC。
总结
BFC 的核心价值可以归纳为三点:
- 包含浮动:让容器正确计算浮动子元素的高度。
- 隔离 margin 折叠:阻止垂直外边距跨 BFC 边界折叠。
- 避开外部浮动:使布局区域不与浮动盒子重叠。
在现代 CSS 中,需要主动创建 BFC 时,通常优先选择:
.container {
display: flow-root;
}