技术知识文章集合TECHNICAL ARCHIVE · 457 DOCUMENTS

显示模式

登录
ARCHIVE DOCUMENTHTML

什么是 BFC

所属馆藏
HTML
文件格式
Markdown
原始路径
HTML/08-什么是 BFC
本文目录7 个章节
  1. 什么是 BFC
  2. 开启 BFC 能解决什么问题
  3. 哪些元素会创建 BFC
  4. 三大典型场景
  5. 最佳实践:display: flow-root
  6. 总结
  7. 参考资料

什么是 BFC

什么是 BFC

BFC(Block Formatting Context,块级格式化上下文)是 CSS 渲染页面时的一个概念,指页面中一块独立的布局区域

W3C 的解释是:BFC 决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用。当涉及到可视化布局时,BFC 提供了一个环境,HTML 元素在其中按照块级布局的规则进行排列。

通俗地说:BFC 是一个独立的布局环境,内部子元素的布局不会影响外部,外部也不会影响它

需要注意:BFC 不是某个 CSS 属性,它是渲染过程中的一种布局区域。我们无法直接"设置 BFC",而是通过某些 CSS 属性值的副作用来创建(开启)它。

开启 BFC 能解决什么问题

一个元素创建了新的 BFC 后,会获得以下三个特性:

  1. 包含内部浮动:就算其子元素浮动,元素自身高度也不会塌陷(能"包住"浮动子元素);
  2. 排除外部浮动:自己不会被其他浮动元素覆盖,而是紧贴在浮动元素旁边排布;
  3. 阻止 margin 合并:该元素与其子元素之间、该元素与外部元素之间的垂直 margin 不再合并。

注意第 3 点的边界:开启 BFC 阻止的是该元素与子元素之间该元素与外界的 margin 合并;但 BFC 内部相邻子元素之间的 margin 仍然会正常合并,这是块级布局的默认行为。

哪些元素会创建 BFC

满足以下任一条件的元素会创建新的 BFC:

  • 文档的根元素<html>,页面加载后就默认存在);
  • 浮动元素float 不为 none
  • 定位元素position: absolutefixedsticky
  • display: inline-block
  • 表格类
    • display: table-cell(HTML 中默认是 tdth);
    • display: table-caption(默认是 caption);
    • display: tabletable-rowtable-row-grouptable-header-grouptable-footer-groupinline-table——它们会让内部生成匿名 table cell,间接创建 BFC;
  • 块级盒子overflow 不为 visible 且不为 clip(即 autoscrollhidden 等);
  • display: flow-root最推荐,见下文);
  • flex 项display: flex / inline-flex 容器的直接子元素(前提是该子元素自身不是 flex、grid 或 table 容器);
  • grid 项display: grid / inline-grid 容器的直接子元素(前提同上);
  • 多列容器column-countcolumn-width 不为 auto
  • column-span: all 的元素(即使没有包裹在多列容器中);
  • contain: layoutcontentstrict 的元素;
  • container-type 不为 normal 的元素(容器查询元素)。

注意区分:flex/grid 容器本身创建的是 flex 格式化上下文(FFC)或 grid 格式化上下文(GFC),严格来说不是 BFC——只是行为类似(内部 margin 不合并、不与外部浮动重叠)。创建 BFC 的是它们的子元素

三大典型场景

1. 高度塌陷(包含内部浮动)

父元素没有高度、子元素又全部浮动时,父元素高度会塌陷为 0:

<div class="container">
  <div class="float-item">我是浮动的子元素</div>
</div>
.container {
  border: 2px solid #333;
  /* 子元素浮动后,这里高度塌陷为 0,边框"包不住"子元素 */
}

.float-item {
  float: left;
  width: 200px;
  height: 100px;
  background-color: #74b9ff;
}

给父元素开启 BFC,即可让它"包住"浮动的子元素:

.container {
  display: flow-root; /* 高度不再塌陷 */
}

2. 不被浮动元素覆盖(排除外部浮动)

右侧元素会被左侧浮动元素部分覆盖(文字环绕效果的由来):

<div class="float-box">左浮动</div>
<div class="normal-box">正常块级元素</div>
.float-box {
  float: left;
  width: 150px;
  height: 100px;
  background-color: #ffeaa7;
}

.normal-box {
  /* 未开启 BFC:会与浮动元素重叠排布,文字环绕 */
  /* 开启 BFC:整体排布在浮动元素右侧,不被覆盖 */
  overflow: hidden; /* 方式之一 */
}

开启 BFC 后,.normal-box 会识别浮动元素的存在,紧贴其右边缘排布。这也是"两栏自适应布局"的经典原理。

3. 父子 margin 合并(margin 塌陷)

子元素的 margin-top 会"穿透"到父元素外面:

<div class="parent">
  <div class="child">子元素</div>
</div>
.parent {
  width: 300px;
  background-color: #55efc4;
  /* 未处理时:child 的 margin-top 会跑到 parent 外面 */
}

.child {
  margin-top: 50px;
}

给父元素开启 BFC,父子的 margin 就不会再合并:

.parent {
  display: flow-root;
}

最佳实践:display: flow-root

开启 BFC 的方式很多,但各有副作用:

方式副作用
overflow: hidden会裁剪溢出内容、隐藏滚动
float: left元素自身脱离文档流
display: inline-block改变元素显示类型
position: absolute脱离文档流
display: flow-root无副作用,专为此而生

display: flow-root 的含义就是"创建一个块级盒子,且它是一个新的 BFC 根",语义明确、无任何布局副作用,是现代浏览器中开启 BFC 的首选。主流浏览器均已支持。

总结

  1. BFC 是一块独立的布局区域,内部元素不影响外部,外部也不影响内部;
  2. BFC 的三大作用:包含内部浮动排除外部浮动阻止 margin 合并
  3. 阻止 margin 合并仅限于"该元素与子元素/外界"之间,BFC 内部子元素之间的 margin 仍会合并;
  4. 创建 BFC 的方式很多(根元素、浮动、绝对定位、overflow、表格类、flex/grid 项等),但首选 display: flow-root——它无副作用、语义清晰;
  5. 不要为了开启 BFC 而开启,只在需要解决上述三类布局问题时使用。

参考资料

457 DOCUMENTS · 10 COLLECTIONS
ARCHIVE SEARCH457 篇文章

SEARCH GUIDE

输入关键词开始搜索

支持搜索文章标题、所属分类和原始文档路径。

按分类浏览

10 COLLECTIONS