前言
在前端开发中,我们经常会遇到这样的场景:左侧固定宽度做导航,右侧自适应填满剩余空间做内容区;或者左右两侧固定,中间自适应的经典三栏布局。
很多人会直接使用 Flexbox 或 Grid 来解决,这当然没问题。但如果面试官追问:“如果不使用 Flex 和 Grid,仅用传统 CSS,你如何实现?背后的原理是什么? ”
这时候,就需要请出 CSS 布局中的“定海神针”—— BFC(Block Formatting Context,块级格式化上下文) 了。
一、 到底什么是 BFC?
官方定义很绕,用人话来说:BFC 就像是一个封闭的、独立的“结界”。
在这个结界里面的元素怎么折腾(比如浮动、塌陷),都不会影响到外面的元素;同理,外面的元素也进不来干扰里面。
它有三个维度的核心规则:怎么创建它、它内部怎么排版、它跟外部怎么相处。
二、 怎么召唤出 BFC?(创建规则)
记住一个前提:普通的块级元素(比如最常见的 div)默认不是 BFC,必须通过特定条件触发。
以下是触发 BFC 的常见方式:
- 根元素:
<html>标签本身就是最大的 BFC。 - 浮动元素:给元素加上
float: left / right(只要不是 none)。 - 绝对/固定定位:
position: absolute / fixed。 - 行内块元素:
display: inline-block。 - 表格相关:
display: table-cell等(现在极少用来做布局)。 - 🔥 溢出非可见(最常用) :
overflow: hidden / auto / scroll。(注意:默认的overflow: visible不会触发)。 - 现代布局:
display: flex / grid / inline-flex / inline-grid(这会使其成为 Flex/Grid 容器,内部自然形成独立的 BFC 机制)。
三、 BFC 内部布局规则
当一个元素变成了 BFC,它内部就会遵守以下规矩:
-
垂直排列:BFC 内的块级盒子只能从上到下垂直排布,绝对不可能横向并排。
-
Margin 折叠现象:在同一个 BFC 中,相邻的两个块级元素的垂直外边距会发生“折叠”。比如上面的
margin-bottom: 10px,下面的margin-top: 20px,两者之间的真实距离是取最大值20px,而不是相加的30px。- 破解之法:把这两个元素放在两个不同的 BFC 结界里,就不会折叠了。
-
触边对齐(⚠️易错点) :BFC 内部的每个盒子的左外边缘,都会死死贴住这个 BFC 容器的左边缘。
- 注意:这里说的是“盒子的边缘”贴住容器,但盒子里的“文字内容”是活体,看到浮动元素会主动避让,形成“文字环绕浮动元素”的效果。这也是为什么普通 div 会被浮动覆盖,而文字不会。
四、 BFC 的“对外防御机制”(外部交互规则)
这是 BFC 最核心的价值所在,它拥有两大“超能力”:
- 包含内部浮动(解决高度塌陷) :如果 BFC 里面有子元素浮动了,按理说父元素会失去高度(高度塌陷)。但只要父元素触发了 BFC,它就会强行计算并把所有浮动子元素包裹在内。
- 排除外部浮动(防重叠) :如果一个 BFC 旁边有一个浮动的元素,这个 BFC 绝对不会去跟那个浮动元素重叠,它会自动收缩自己的宽度,给浮动元素让出位置。
正是这第二个超能力,造就了经典的浮动布局!
五、 实战演练:用 BFC 搞定两列与三列布局
1. 经典两列式布局(左固定,右自适应)
需求:左侧导航栏宽 200px,右侧内容区撑满剩余宽度。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BFC实现两列布局</title>
</head>
<style>
* {
margin: 0;
padding: 0;
}
.left {
width: 200px;
height: 500px;
float: left; /* 1. 左侧脱标浮动 */
background-color: #ccc;
}
.right {
height: 500px;
overflow: hidden; /* 2. 右侧触发 BFC */
background-color: #333;
color: #fff;
/* 加点内边距让文字不贴边,更好看 */
padding: 20px;
/* 因为加了padding,需要用box-sizing保证不撑大盒子 */
box-sizing: border-box;
}
</style>
<body>
<!-- 注意:HTML的class属性里不需要加 . 号 -->
<div class="left">左侧固定区域 (200px)</div>
<!-- 这里使用上面定义好的 .right 类名 -->
<div class="right">右侧自适应区域 (无论浏览器多宽,我都会填满剩下的空间,且不会覆盖左侧)</div>
</body>
</html>
原理解析:
左侧 float 起来了,右侧本是一个普通的块级 div,按理说它会无视浮动,占满整行跑到左侧下面去。但我们给右侧加了 overflow: hidden 触发了 BFC。根据 BFC 【排除外部浮动】 的规则,右侧这个“结界”拒绝与左侧的浮动区域重叠,于是它老老实实退缩到了浮动元素的右边,剩余多少宽度它就占多少,完美实现自适应!
2. 经典三列式布局(左右固定,中间自适应)
需求:左侧 200px,右侧 200px,中间自适应。
HTML 结构:
代码生成完成
HTML代码
CSS 代码:
.left {
width: 200px; height: 500px;
float: left;
background: #ccc;
}
.right {
width: 200px; height: 500px;
float: right;
background: #aaa;
}
.center {
height: 500px;
overflow: hidden; /* 触发 BFC */
background: #333;
color: #fff;
}
原理解析:
左右两侧分别向左向右浮动,脱离了文档流。中间的 div 加上 overflow: hidden 触发 BFC 后,它既要躲避左边的浮动,又要躲避右边的浮动。两头都被挤压,最终只能乖乖夹在中间,剩下的空间全归它所有。
总结
在 Flexbox 和 Grid 横行的今天,我们写业务可能很少再手写 float + BFC 布局了。但是,理解 BFC 绝不是为了写古董代码。
当你在页面中遇到莫名的“高度塌陷”、遇到“Margin 合并不生效”、遇到“浮动元素覆盖了后续内容”时,如果你脑子里能瞬间闪过 BFC 的那几条规则,你能在一分钟内定位并解决问题。
BFC 不是过时的技术,而是透视 CSS 底层渲染逻辑的一把钥匙。 掌握了它,你的 CSS 功力才算真正跨入了进阶的大门。