1. BFC的定义

BFC - Block Formatting Context 块级格式化上下文 BFC的定义,在官方文档到中,是这么介绍BFC的。

A block formatting context contains everything inside of the element creating it that is not also inside a descendant element that creates a new block formatting context.

翻译过来便是:一个BFC区域包含创建该上下文元素的所有子元素,但是不包括创建了新的BFC的子元素的内部元素。

比如:

1
2
3
4
5
6
7
8
9
10
<div class="box1" id="bfc1">
<div class="box2"></div>
<div class="box3"></div>
<div class="box4"></div>
<div class="box5" id="bfc2">
<div class="box6"></div>
<div class="box7"></div>
<div class="box8"></div>
</div>
</div>

以上面这段代码来解释,#bfc1是一块 BFC 区域,这块区域包括了box2、box3、box4、box5,但是并不包括box5下的子元素box6、box7、box8。而#bfc2也是一块 BFC 区域,包括了box6、box7、box8。所以,每一个BFC区域只包括其子元素,不包括其子元素的子元素。

2. BFC的触发条件

并不是任意一个元素都可以被当做BFC,只有当这个元素满足以下任意一个条件的时候,这个元素才会被当做一个BFC。

body根元素

设置浮动,不包括none

设置定位,absoulte或者fixed

行内块显示模式,inline-block

设置overflow,即hidden,auto,scroll

表格单元格,table-cell

弹性布局,flex

比如:

1
2
3
4
5
6
7
8
<body>
<div class="box1"></div>
<div class="box2"></div>
<div class="box3" id="bfc">
<div class="box4"></div>
<div class="box5"></div>
</div>
</body>

首先,以上的代码中,body元素是一个BFC,因为他满足BFC的第一个触发条件(body根元素)。但是#bfc并不是一个BFC区域,因为他并没有满足任何一个触发条件。如果我们要使他变为一个BFC区域,让其满足任意一个触发条件即可。

比如:

1
2
3
4
5
<style>
#bfc{
overflow: hidden;
}
</style>

当#bfc元素设置为 overflow: hidden 后,满足触发条件,此时#bfc就是一个BFC区域,这个BFC区域包括box4和box5。

3. BFC解决问题

理解了BFC的触发条件后,就需要使用BFC的特点来解决布局时遇到的问题了。

首先要明白BFC有一个特点:每一个BFC区域都是相互独立,互不影响的。

3.1 解决外边距的塌陷问题

我们设置两个class值为box的div盒子,并把他的margin设置为100px

1
2
3
4
<body>
<div class="box"></div>
<div class="box"></div>
</body>
1
2
3
4
5
6
7
8
<style>
.box {
width: 200px;
height: 200px;
background-color: red;
margin: 100px;
}
</style>

这时你会发现,我们对.box设置了四个方向的margin,都为100px。那么上一个盒子和下一个盒子之间的距离应该是 100px+100px=200px。但事实并非如此,上下两个盒子之间的距离只有100px。

这就是margin的塌陷,两段margin重叠到了一块,互相影响。那么要解决这个问题,就要用到BFC的特点:每一个BFC区域都是相互独立,互不影响的。所以,我们可以将这两个盒子放到两个BFC区域中

1
2
3
4
5
6
7
8
<body>
<div class="bfc">
<div class="box"></div>
</div>
<div class="bfc">
<div class="box"></div>
</div>
</body>
1
2
3
4
5
6
7
8
9
10
11
<style>
.box {
width: 200px;
height: 200px;
background-color: red;
margin: 100px;
}
.bfc{
overflow: hidden;
}
</style>

3.2 利用BFC解决包含塌陷

当一个父子关系的盒子,给子元素添加margin-top,会带着父元素盒子一起

1
2
3
4
5
<body>
<div class="father">
<div class="son"></div>
</div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
<style>
.father {
width: 300px;
height: 300px;
background-color: red;
}
.son{
width: 100px;
height: 100px;
background-color: gold;
margin-top: 50px;
}
</style>

原本是子元素盒子与父元素盒子顶部距离50px,由于margin塌陷问题,导致盒子的内部布局影响到了外部。

这时候,我们可以通过触发BFC,把父元素盒子变为一个BFC区域,由于BFC的特点:每一个BFC区域都是相互独立,互不影响的。 外面的父元素BFC区域影响不了bodyBFC区域,就不会改变外部布局了。

1
2
3
4
5
6
.father {
width: 300px;
height: 300px;
background-color: red;
overflow: hidden;
}

3.3 当浮动产生影响的时候,可以利用BFC来清除浮动的影响

设置一个没有设高度的父元素盒子,包含6个子元素

1
2
3
4
5
6
7
8
9
10
<body>
<div class="father">
<div class="son"></div>
<div class="son"></div>
<div class="son"></div>
<div class="son"></div>
<div class="son"></div>
<div class="son"></div>
</div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
<style>
.father {
width: 300px;
background-color: red;
}
.son{
width: 100px;
height: 30px;
background-color: gold;
border: 1px solid greenyellow;
}
</style>

当给所以子元素都设置浮动后,父元素就会失去原有的高度

1
2
3
4
5
6
7
.son{
width: 100px;
height: 30px;
background-color: gold;
border: 1px solid greenyellow;
float: left;
}

所以,我们可以触发BFC,来清除浮动带来的影响

1
2
3
4
5
.father {
width: 300px;
background-color: red;
overflow: hidden;
}

3.4 BFC可以阻止标准流元素被浮动元素覆盖

设置红色盒子浮动,蓝色盒子标准流

1
2
3
4
<body>
<div class="red"></div>
<div class="blue"></div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
<style>
.red {
width: 200px;
height: 200px;
background-color: red;
float: left;

}
.blue{
height: 300px;
background-color: blue;
}
</style>

可以看到,红色盒子浮动覆盖了蓝色盒子

但是如果蓝色盒子触发了BFC

1
2
3
4
5
.blue{
height: 300px;
background-color: blue;
overflow: hidden;
}

可以看到,蓝色盒子触发了BFC后,浮动元素无法覆盖蓝色盒子了,并且我们还可以利用这个特性来实现蓝色盒子的自适应功能。

4. 总结

一个BFC区域只包含其子元素,不包括其子元素的子元素。

并不是所有的元素都能成为一块BFC区域,只有当这个元素满足条件的时候才会成为一块BFC区域。

不同的BFC区域之间是相互独立的,互不影响的。利用这个特性我们可以让不同BFC区域之间的布局不产生影响。