05BFC 块级格式化上下文

BFC(Block Formatting Context,块级格式化上下文)是 CSS 里最著名的「看不见的概念」。 其实它一点也不玄:一块自成一体的独立布局区域—— 浮动章的高度塌陷、盒模型章的 margin 合并,答案都是它。学会触发 BFC,等于拿到一把修复布局的万能钥匙。

约 14 分钟 4 个动手实验 布局排障必备

一、BFC 是什么:一块「独立自治区」

BFC 全称 Block Formatting Context(块级格式化上下文)。 它不是某个属性,而是一种渲染状态:满足特定条件的元素,会圈出一块 「独立自治区」——区内的布局影响不到区外,区外的规则也进不了区内。

最贴切的比喻是防水袋:把东西装进袋子封好口, 袋子里就算泡着水(浮动、margin),也漏不到外面;外面的浪(相邻元素)同样打不湿袋子里的内容。 一个元素一旦形成 BFC,它就变成一个封好口的防水袋。

页面其他内容:袋子里发生什么,我一概感觉不到 ↓
BFC 防水袋
浮动元素?袋内自己兜住
margin?到袋口为止
BFC 两条铁律:① 计算高度时把浮动子元素也算进去;② 区域内外的 margin 互不合并、区域不与外部浮动重叠
BFC 在 DevTools 里没有一个叫「BFC」的开关可看——它是条隐性规则。 判断方法很朴素:给元素加上触发条件(如下一节的 display: flow-root), 塌陷、合并、重叠这些毛病立刻消失,就说明 BFC 成立了。

二、触发方式速查表:怎么造一个 BFC

让一个元素成为 BFC 的方法很多,但绝大多数是「顺带的副作用」—— 真正为造 BFC 而生的只有 display: flow-root。

BFC 常见触发方式:副作用越小越推荐
触发方式副作用推荐度
display: flow-root无!专为造 BFC 而生的现代专用值★★★★★ 首选
overflow: hidden / auto / scroll溢出内容被裁切,auto / scroll 可能出现滚动条★★★ 确定无溢出时可用
display: inline-block变成行内块:宽度收缩、换行有缝隙★★
float: left / right自己先浮动起来,布局跟着连锁变化★ 基本只见于老代码
position: absolute / fixed脱离文档流,要重新操心定位★ 别为 BFC 用它
display: flex / grid(容器)布局模式整个改变顺带的:flex/grid 容器天然是 BFC
contain: content / layout语义是渲染性能隔离了解即可
记忆口诀:造 BFC,只用 flow-root。 其余方式要么裁内容、要么改布局,都是「为了治感冒把胳膊截了」—— 除非老项目兼容性要求,否则一律 display: flow-root。

三、应用一:清除浮动,治好高度塌陷

浮动章埋过一颗雷:子元素全部浮动后脱离文档流, 父元素当它不存在,高度塌成 0,边框只剩一条线,后面的元素直接顶上来——这就是「高度塌陷」。 BFC 的第一条铁律正是解药:BFC 计算高度时,会把内部的浮动子元素也包进去。

塌陷现场:父级高度塌成一条虚线,包不住两个浮动的孩子。把 .parent 里 display: flow-root 那行注释打开(删掉 /* */),父级立刻把孩子「捞」回来
这就是「清除浮动」的本质:早年大家给父级末尾塞空 div 写 clear: both,或者用 .clearfix::after 伪元素大法—— 殊途同归,都是想办法让父级承认浮动孩子的高度。 现在一句 display: flow-root 就够了。

四、应用二:阻止 margin 合并

盒模型章讲过「父子 margin 穿透」: 父元素没有 padding / border 挡着时,第一个孩子的 margin-top 会合并到父级身上, 看起来像「孩子把父级整个顶跑了」。BFC 的第二条铁律: BFC 区域内外的 margin 互不合并——袋子一封口,margin 就漏不出去了。

穿透现场:孩子的 40px 把整个粉色父级顶了下去,父级内部却一点空隙都没有。把 .parent 里 overflow: hidden 的注释打开,间距立刻回到父级「肚子」里
盒模型章给的「防合并三板斧」里,父元素加 padding / border 会改变盒子的视觉效果, 而触发 BFC 是纯逻辑修复——外观零变化,只是告诉浏览器:这块区域的 margin 自己管自己。

五、应用三:两栏自适应,文字不再环绕

「左图右文」的经典布局:图片浮动后,文字默认会环绕它排, 流过长长的文字会绕到图片下面去——做图文混排是特性,做两栏布局就是灾难。 BFC 的第三条特性:BFC 区域不会与外部浮动元素重叠。 给文字块触发 BFC,它就乖乖缩成右边一栏,和图片平起平坐。

环绕现场:文字流到了图片下方。把 .text 里 overflow: hidden 的注释打开,文字块立刻变成规整的右栏——再删掉对比环绕效果
这套「左浮右 BFC」就是老式媒体对象(Media Object)布局: 头像、图标固定宽,文字自适应剩余宽度,图片多宽文字自动让多宽。 现代项目里同样的效果用 display: flex 更直观—— 下一章 Flex 就讲,这里先记住 BFC 这条老路。

六、flow-root vs overflow:hidden 的取舍

既然 overflow: hidden 也能触发 BFC,为什么还要推荐 display: flow-root?因为 overflow 的本职是溢出处理: 它会把探出盒子的内容裁掉——下拉菜单、气泡角标、 悬浮提示,探出去的部分统统被「切头」。

左边徽章探出容器被裁掉一半,右边完好无损:把 .a 的 overflow: hidden 改成 display: flow-root,徽章立刻恢复
两种主流触发方式正面对比:同为 BFC,待遇天差地别
对比项overflow: hiddendisplay: flow-root
溢出内容(下拉菜单、角标)被裁切,探出去就消失原样显示
滚动条auto / scroll 值可能冒出滚动条永不出现
语义顺手借来的副作用,读代码要想一层明明白白:我就是来造 BFC 的
兼容性全浏览器通吃现代浏览器全支持(仅 IE 不认识)
推荐场景老项目维护、确定无溢出现代项目清除浮动 / 防合并的首选
真实的线上事故:卡片为了清浮动写了 overflow: hidden, 后来产品要在卡片右上角加个「NEW」角标,探出去的部分死活不显示—— 查了半天才发现是被 overflow 裁了。除非你就是想裁切,否则别用 overflow 当清浮动的工具。

七、本章小结

  • BFC(Block Formatting Context,块级格式化上下文)是一块独立布局区域:区内布局不影响区外,区外也影响不到区内——「防水袋」。
  • BFC 三条铁律:计算高度包含浮动子元素;区域内外 margin 不合并;区域不与外部浮动重叠。
  • 触发方式首选 display: flow-root——无副作用的专用值;overflow: hidden 会裁切溢出内容,只在老代码里将就用。
  • 三大应用:① 清浮动治高度塌陷;② 阻止父子 / 相邻 margin 合并;③ 做左图右文两栏自适应。
  • flex / grid 容器天然是 BFC——所以弹性盒布局里从来不会塌陷,这也是现代布局省心的一部分。
  • 面试加分项:能说清「BFC 不是属性而是渲染状态」,以及 flow-root 与 overflow 的取舍。
动手练习:① 复刻第三节的塌陷 lab,但改用 overflow: auto 修, 观察会不会冒出滚动条;② 给第四节的孩子再加一个 margin-bottom: 30px, 父级触发 BFC 前后分别看底部间距的变化;③ 用「左浮图 + 右侧 BFC 文字块」做一张新闻卡片, 再把图片 float 改成 right,确认文字栏自动换到左边。