本文主要介绍什么是BFC?怎么触发BFC?BFC有什么作用?可以解决哪些问题?
1.什么是BFC
先看下官方的解释:
区块格式化上下文(Block Formatting Context,BFC)是 Web 页面的可视 CSS 渲染的一部分,是块级盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。
官方的描述有点抽象,其实可以把BFC理解成就是css的块级作用域。
具有 BFC 特性的元素可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,并且 BFC 具有普通容器所没有的一些特性。
2.怎么触发BFC
下列方式会创建块格式化上下文:
- 文档的根元素(
<html>
)。 - 浮动元素(即 float 值不为
none
的元素)。 - 绝对定位元素(position 值为
absolute
或fixed
的元素)。 - 行内块元素(display 值为
inline-block
的元素)。 - overflow 为hidden,scroll,auto的元素,值不为
visible
或clip
的块级元素。 - display 值为
flow-root
的元素。 - 弹性元素(display 值为
flex
或inline-flex
元素的直接子元素),如果它们本身既不是弹性、网格也不是表格容器。 - 网格元素(display 值为
grid
或inline-grid
元素的直接子元素),如果它们本身既不是弹性、网格也不是表格容器。 - 表格单元格(display 值为
table-cell
,HTML 表格单元格默认值)。 - 表格标题(display 值为
table-caption
,HTML 表格标题默认值)。 - 匿名表格单元格元素(display 值为
table
(HTML 表格默认值)、table-row
(表格行默认值)、table-row-group
(表格体默认值)、table-header-group
(表格头部默认值)、table-footer-group
(表格尾部默认值)或inline-table
)。 - contain 值为
layout
、content
或paint
的元素。 - 多列容器(column-count 或 column-width (en-US) 值不为
auto
,且含有column-count: 1
的元素)。 column-span
值为all
的元素始终会创建一个新的格式化上下文,即使该元素没有包裹在一个多列容器中(规范变更、Chrome bug)
display: flow-root 是 CSS 中的一个属性,它可以让元素块状化,同时包含格式化上下文BFC。当应用 display: flow-root 声明后,无论是内联元素还是原本就是块级元素,都会变成块级元素,并建立新的块级格式上下文(BFC)
那么BFC的作用是什么?可以解决哪些问题?接下来会有详细介绍
3.BFC可以解决哪些问题
-
包含内部浮动(解决父元素塌陷问题)
<style>
.box {
border: 1px solid pink;
background-color: #79caf3;
}
.float {
float: left;
width: 100px;
height: 100px;
background-color: #3cea42;
}
</style>
<div class="box">
<div class="float">我是浮动元素</div>
<div>我是父元素里面的其他元素</div>
</div>
父元素没有触发BFC,父元素的高度为auto时,不会包含浮动元素的高度,造成浮动元素塌陷。
解决办法:父元素触发BFC
<style>
.box {
border: 1px solid pink;
background-color: #79caf3;
}
.float {
float: left;
width: 100px;
height: 100px;
background-color: #3cea42;
}
</style>
<div class="box" style="overflow: auto"> //父元素触发BFC
<div class="float">我是浮动元素</div>
<div>我是父元素里面的其他元素</div>
</div>
事实上,BFC的高度是auto的情况下,是如下方法计算高度的
-
1.如果只有inline-level,是行高的顶部和底部的距离;
-
2.如果有block-level,是由最顶层的块上边缘(margin-top)和最底层块盒子的下边缘(margin-bottom)之间的距离
-
3.如果有绝对定位元素,将被忽略(不计算高度);
-
4.如果有浮动元素,那么会增加高度以包括这些浮动元素的下边缘
因此,将浮动元素的父元素触发BFC,其会增加高度以包括浮动元素的底部,达到解决父元素高度塌陷的问题。
但是,这种方式不能解决绝对定位元素的父元素塌陷问题。
-
排除外部浮动(实现两列布局)
<style>
.box {
border: 5px solid pink;
background-color: #79caf3;
}
.float {
float: left;
width: 100px;
height: 100px;
background-color: #3cea42;
margin-right: 20px;
opacity: 0.5;
}
.content {
border: 5px solid rgb(23, 12, 227);
background-color: #ef4fd2;
}
</style>
<div class="box">
<div class="float">我是在BFC里面的浮动元素</div>
<div class="content">
我是父元素里面的其他元素,也是BFC元素
</div>
</div>
<style>
.box {
border: 5px solid pink;
background-color: #79caf3;
}
.float {
float: left;
width: 100px;
height: 100px;
background-color: #3cea42;
margin-right: 20px;
opacity: 0.5;
}
.content {
border: 5px solid rgb(23, 12, 227);
background-color: #ef4fd2;
}
</style>
<div class="box">
<div class="float">我是在BFC里面的浮动元素</div>
<div class="content" style="display: flow-root">
我是父元素里面的其他元素,也是BFC元素
</div>
</div>
正常文档流中建立的 BFC 不得与元素本身所在的块格式化上下文中的任何浮动的外边距重叠。
我们可以使用BFC的这一特性实现双列布局,不过弹性盒子是在现代 CSS 中实现多列布局的更有效的方法。
-
阻止外边距重叠
在同一个BFC中,两个相邻元素直接垂直方向的外边距可能会重叠,可以创建新的 BFC 避免两个相邻元素之间的外边距重叠。
注意:水平方向上的margin(margin-left、margin-right)永远不会重叠。
1.相邻兄弟元素之间外边距重叠
<style>
.red {
margin: 20px;
width: 100px;
height: 100px;
background-color: #da5127;
}
.blue {
margin: 20px;
width: 100px;
height: 100px;
background-color: #3d48d7;
}
</style>
<!-- 兄弟元素直接外边距重叠 -->
<div class="red"></div>
<div class="blue"></div>
折叠之后的取值:两个值进行比较,取较大的值
怎么解决兄弟元素上下外边距折叠?
<style>
.red {
margin: 20px;
width: 100px;
height: 100px;
background-color: #da5127;
}
.blue {
margin: 20px;
width: 100px;
height: 100px;
background-color: #3d48d7;
}
</style>
<div class="red"></div>
<div style="display: flow-root">
<div class="blue"></div>
</div>
我们将第二个 <div>
包裹在另外一个 <div>
之中,以创建一个新的 BFC,防止外边距重叠。
2.父子元素上外边距重叠
margin-top传递
如果块级元素的顶部线和父元素的顶部线重叠,那么这个块级元素的margin-top值会传递给父元素
<style>
.father {
width: 200px;
height: 200px;
background-color: #8ad7e8;
}
.son {
margin-top: 20px;
width: 100px;
height: 100px;
background-color: #e765b9;
}
</style>
<div class="father">
<div class="son"></div>
</div>
3.父子元素下外边距重叠
margin-bottom传递
如果块级元素的底部线和父元素的底部线重合,并且父元素的高度是auto,那么这个块级元素的margin-bottom值会传递给父元素
<style>
.father-botton {
width: 200px;
background-color: #8ad7e8;
}
.son-botton {
margin-bottom: 20px;
width: 100px;
height: 100px;
background-color: #e765b9;
}
.other {
width: 200px;
height: 200px;
background-color: #71f0a4;
}
</style>
<!-- 父子兄弟下外边距重叠 -->
<div class="father-botton">
<div class="son-botton"></div>
</div>
<div class="other"></div>
如何解决父子之间的外边距传递?
- 父元素设置padding-top\padding-bottom
- 父元素设置border
- 父元素触发BFC
<style>
.father-botton {
overflow: auto;
border: 1px solid #71f0a4;
padding: 10px;
width: 200px;
background-color: #8ad7e8;
}
.son-botton {
margin-bottom: 20px;
width: 100px;
height: 100px;
background-color: #e765b9;
}
.other {
width: 200px;
height: 200px;
background-color: #71f0a4;
}
</style>
<!-- 父子兄弟下外边距重叠 -->
<div class="father-botton">
<div class="son-botton"></div>
</div>
<div class="other"></div>
参考链接:
区块格式化上下文 - Web 开发者指南 | MDN (mozilla.org)
掌握外边距折叠 - CSS:层叠样式表 | MDN (mozilla.org)
10 分钟理解 BFC 原理 - 知乎 (zhihu.com)
什么是BFC?面试前看这一篇就够了 - 知乎 (zhihu.com)