# BFC

8 min read
Table of Contents

BFC(Block Formatting Context) 块级格式化上下文。它是块级布局发生的区域,也是浮动与其他元素交互的区域。

具有 BFC 特性的元素可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,并且 BFC 具有普通容器所没有的一些特性。即 BFC 为一个独立的区域,内部元素不管怎么变化,都不影响外部元素。

渲染规则

BFC 有一套属于自己的渲染规则:

  • 内部的盒子会在垂直方向上一个接一个地放置
  • 同一个 BFC 的两个相邻的盒子 margin 会发生重叠
  • 每个元素的左边距会与包含块的左边距相接触
  • BFC 的区域不会与 float 元素区域重叠
  • 计算 BFC 的高度时,浮动子元素也参与计算
  • BFC 就是页面上一个隔离的独立容器,里面子元素不会影响到外面的元素

触发 BFC

只要元素满足任一条件就可以触发 BFC

  • 文档根元素 <html>
  • 浮动(除 float: none 以外)
  • 绝对定位元素(postion 是 absolute 或 fixed)
  • 行内块元素(display 为 inline-block)
  • overflow (除 visible 和 clip 以外)
  • display: flow-root
  • Flex 项(display 为 flex 或 inline-flex)
  • 栅格项(display 为 grid 或 inline-grid)

主要作用

通常情况下,会为布局和清除浮动创建一个新的 BFC,而非改变布局,因为创建一个新的 BFC 的元素会:

  • 包含内部浮动
  • 排除外部浮动
  • 防止边距叠加

包含内部浮动

让浮动内容和旁边的内容高度相同。在下面例子中,浮动元素脱离文档流,所以容器不能撑起浮动元素的高度。

浮动元素
容器内的文段
<section>
<div class="box">
<div class="float">浮动元素</div>
<div>容器内的文段</div>
</div>
</section>
section {
height: 150px;
}
.box {
background-color: rgb(224, 206, 247);
border: 5px solid rebeccapurple;
}
.box[style] {
background-color: aliceblue;
border: 5px solid steelblue;
}
.float {
float: left;
width: 200px;
height: 100px;
background-color: rgba(255, 255, 255, 0.5);
border: 1px solid black;
padding: 10px;
}

根据上面设置 BFC 的方式,选择两种方式:

  • 设置 overflow: auto 新建一个包含浮动 BFC 的容器。
  • 设置 display: flow-root 创建一个新的 BFC 且没有副作用。
浮动元素
容器设置了overflow:auto的文段
<section>
<div class="box" style="overflow:auto">
<div class="float">浮动元素</div>
<div>容器设置了<code>overflow:auto</code>的文段</div>
</div>
</section>
<section>
<div class="box" style="display:flow-root">
<div class="float">浮动元素</div>
<div>容器设置了<code>display:flow-root</code>的文段</div>
</div>
</section>

除创建 BFC 外,还有一种经典的清除浮动方式:使用 :after 伪元素在容器末尾添加一个不可见的块,通过 clear: both 将浮动元素包围在容器内。

.container:after {
content: '';
display: block;
height: 0;
clear: both;
visibility: hidden;
}

下面左边是未清除浮动的容器(高度塌陷、浮动元素溢出),右边是应用了 :after 清除浮动的容器(容器包裹浮动元素):

<style>
.cf-demo {
border: 1px solid black;
margin-bottom: 16px;
}
.cf-demo .cf-float {
float: left;
width: 70px;
height: 40px;
text-align: center;
line-height: 40px;
color: #fff;
}
.cf-clearfix:after {
content: '';
display: block;
height: 0;
clear: both;
visibility: hidden;
}
</style>
<!-- 未清除浮动:浮动元素溢出容器 -->
<div class="cf-demo">
<span class="cf-float" style="background: #FFBE19">浮动元素</span>
<span class="cf-float" style="background: #14CC8D">浮动元素</span>
普通文本
</div>
<!-- 已清除浮动:容器包裹浮动元素 -->
<div class="cf-demo cf-clearfix">
<span class="cf-float" style="background: #FFBE19">浮动元素</span>
<span class="cf-float" style="background: #14CC8D">浮动元素</span>
普通文本
</div>
浮动元素 浮动元素 普通文本
浮动元素 浮动元素 普通文本

上面的 .cf-clearfix:after 会在容器内容末尾插入一个不可见块状元素,其 clear: both 将两侧浮动元素包围在内,从而撑起容器高度。

排除外部浮动

我们可以一个实例

浮动元素
文本
<section>
<div>
<div class="float">浮动元素</div>
<div class="box">文本</div>
</div>
</section>

给需要排除外部浮动的元素设置 display: flow-root,使其成为一个 BFC。

浮动元素
盒子设置了 display: flow-root
<section>
<div>
<div class="float">浮动元素</div>
<div class="box" style="display: flow-root;">盒子设置了 display: flow-root</div>
</div>
</section>

边距重叠

同一个 BFC 下外边距会发生折叠,创建一个新的 BFC 以避免两个相邻 div 之间的边距崩溃。下面例子中,创建一个新的 div,并设置 overflow: auto; 使其成为一个新的 BFC。

<div style="border: 1px solid #888">
<div style="height: 50px; margin: 10px; background: #DDA0DD;"></div>
<div style="height: 50px; margin: 10px; background: #14CC8D;"></div>
</div>
<div style="border: 1px solid #888">
<div style="height: 50px; margin: 10px; background: #DDA0DD;"></div>
<div style="overflow: auto;">
<div style="height: 50px; margin: 10px; background: #14CC8D;"></div>
</div>
</div>

相关的问题

1. wrap 的高度

<style type="text/css">
.a,
.b,
.c {
box-sizing: border-box;
border: 1px solid;
width: 100px;
}
.wrap {
width: 250px;
background: #ccddee;
}
.a {
height: 100px;
float: left;
background: rebeccapurple;
}
.b {
height: 50px;
float: left;
background: aliceblue;
}
.c {
height: 100px;
display: inline-block;
background: #3388ee;
}
</style>
<div class="wrap">
<div class="a">a</div>
<div class="b">b</div>
<div class="c">c</div>
</div>

如果 c 没有 display: inline-block;,那么 a 将和 c 重叠,虽然文本让出位置,也就是 c 会出现在 a 的下边界下方,但是容器的高度就是 c 的高度 100px。

设置了 display: inline-block; 使得 c 内部形成了 BFC,BFC 不与 float 元素重叠,即 BFC 排除外部浮动。同时 wrap 的宽度限制 250px。所以 c 出现在紧贴着 a 的右边界以及 b 的下边界的位置出现。

a
b
c

参考链接


More Posts

# Promise

7 min read

Promise 对象表示异步操作的最终完成(或失败)及其结果值。

# JS的类型转换

4 min read

将值从一种类型转换为另一种类型通常称为类型转换(type casting),这是显式的情况;隐式的情况称为强制类型转换(coercion)。 — 《你不知道的 JavaScript》