什么是BFC
BFC(Block Formatting Context),即块格式化上下文,是 CSS 视觉格式化模型 (Visual Formatting Model) 的一部分。它是页面中一个独立的渲染区域,该区域拥有一套渲染规则来约束内部元素的布局,且与这个区域外部无关。你可以把它想象成一个“封闭的容器”,容器内的所有元素,包括浮动、定位等,都只会在容器内部进行计算和排列。
BFC产生的背景问题
1. 浮动布局的混乱
在早期的 Web 开发中,float 属性被大量用于页面布局。然而,浮动元素会脱离文档流,导致:
- 父容器高度塌陷
- 文字环绕效果难以控制
- 复杂布局难以实现
2. Margin折叠的不可预测性
相邻块级元素的 margin 会发生折叠,这种行为有时是期望的,有时却会破坏设计:
- 垂直方向上的
margin 折叠
- 父子元素之间的
margin 折叠
- 空元素的
margin 折叠
3. 清除浮动的复杂性
开发者需要各种技巧来清除浮动:
1 2 3 4 5 6
| .clearfix:after { content: ""; display: table; clear: both; }
|
4. 布局隔离的需求
在复杂页面中,开发者希望某些区域的布局不受外部影响,形成独立的布局环境。
BFC解决的核心问题
1. 包含浮动元素
问题:浮动的子元素会导致父容器高度塌陷
1 2 3 4
| <div class="container"> <div class="float-child">浮动元素</div> </div>
|
1 2 3 4 5 6 7 8 9 10 11
| .container { border: 2px solid blue; }
.float-child { float: left; width: 100px; height: 100px; background: red; }
|
BFC解决方案:创建 BFC 的容器会包含其内部的浮动元素
1 2 3 4 5
| .container { border: 2px solid blue; overflow: hidden; }
|
2. 阻止margin折叠
问题:相邻块级元素的 margin 会发生折叠
1 2
| <div class="box1">元素1</div> <div class="box2">元素2</div>
|
1 2 3
| .box1 { margin-bottom: 20px; } .box2 { margin-top: 30px; }
|
BFC 解决方案:将元素放在不同的 BFC 中可以阻止 margin 折叠
1 2 3 4
| <div class="box1">元素1</div> <div class="bfc-wrapper"> <div class="box2">元素2</div> </div>
|
1 2 3
| .bfc-wrapper { overflow: hidden; }
|
3. 排斥浮动元素
问题:普通文档流中的元素会被浮动元素覆盖
1 2
| <div class="float">浮动元素</div> <div class="normal">普通元素,内容可能被浮动元素覆盖</div>
|
BFC 解决方案:BFC 区域不会与浮动元素重叠
1 2 3
| .normal { overflow: hidden; }
|
创建BFC的方法
传统方法
- 根元素(html):天然的
BFC
- 浮动元素:
float 不为 none
- 绝对定位元素:
position 为 absolute 或 fixed
- overflow不为visible:
overflow: hidden/auto/scroll
- display属性:
display: inline-block
display: table-cell
display: table-caption
display: table
现代方法(推荐)
display: flow-root:专门为创建 BFC 设计
1 2 3
| .bfc-container { display: flow-root; }
|
contain 属性:
1 2 3
| .bfc-container { contain: layout; }
|
BFC的布局规则
核心规则
- 内部的块级元素会在垂直方向一个接一个地放置
- 块级元素垂直方向的距离由
margin 决定,相邻元素的 margin 会发生折叠
- 每个元素的左外边缘与包含块的左边缘相接触
BFC 的区域不会与浮动元素重叠
BFC 是页面上的独立容器,内外元素不会相互影响
- 计算
BFC 高度时,浮动子元素也参与计算
实际应用示例
1. 两栏布局
1 2 3 4
| <div class="container"> <div class="sidebar">侧边栏</div> <div class="main">主内容区</div> </div>
|
1 2 3 4 5 6 7 8 9 10
| .sidebar { float: left; width: 200px; background: #f0f0f0; }
.main { overflow: hidden; background: #fff; }
|
2. 清除浮动
1 2 3 4
| <div class="container"> <div class="float-item">浮动项目1</div> <div class="float-item">浮动项目2</div> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12
| .container { display: flow-root; }
.float-item { float: left; width: 200px; height: 150px; margin-right: 20px; background: #ddd; }
|