格式上下文
块级格式上下文(BFC)
BFC 全称是 Block Formatting Context,即块级格式上下文。是 CSS 中的一种 渲染机制。它决定了块级元素如何对它的子元素内容进行布局,以及与子元素同级别的兄弟元素的关系和相互作用,指一个独立的渲染区域或者说是一个隔离的独立容器。
important
通俗来讲,所谓上下文指的就是一个区域,BFC 内的元素和外部的元素相互之间互不干扰,BFC 形成了一个独立的区域,里面的元素遵循这个区域的规则进行布局。之前讲的标准文档流中的一些行为和 BFC 很像,实际上本质就是因为 html 根元素就是一个 BFC。
W3C 规范对此作了详细的描述:
- 浮动元素和绝对定位元素,行内块元素(例如
inline-blocks
,table-cells
, 和table-captions
),以及overflow
值不为visiable
的块级盒子,都会在这些元素内部创建新的 BFC(块级格式上下文)。 - 在 BFC 中,具有标准文档流的特点,即块级盒子独占一行从顶端开始垂直的一个接一个排列,行内盒子在同一行从从左到右排列,并且具有标准流的围观现象,比如空白折叠,在同一个 BFC 中,两个相邻块级盒子的垂直外边距会产生折叠。
让元素内部产生 BFC
- 浮动元素:
float: left | right
- 定位元素:
position: absolute | fixed
- display 的某些取值值:
display: inline-block | flex | table | table-cell | table-caption | inline-table | inline-flex | grid | inline-grid;
- overflow 值不为 visible:
overflow: hidden | scroll | auto
- display: flow-root,新属性,BFC 创建新方式,没有任何副作用,注意浏览器兼容
- html 根元素,整个 html 元素默认就是一个 BFC,如果 html 内只有浮动元素,那么 html 元素是不可能出现塌陷问题的
BFC 布局规则
- 具有 BFC 的盒子,在计算这个盒子高度时,里面的浮动元素也会参与计算(清除浮动原理之一)
- 具有 BFC 的盒子不会被浮动盒子覆盖
- 具有 BFC 的盒子,在页面中是一个独立的容器,内外元素互不影响(可以避免垂直方向的 margin 塌陷)
根据上面的规则,来展示一些例子:
利用 BFC 清除浮动
<div class="container">
<div class="float">我是一个左浮动元素</div>
</div>
.container {
width: 200px;
border: solid;
.float {
width: 100px;
height: 100px;
border: solid;
float: left;
}
}
可以看见父容器高度塌陷了,此时我们让父元素内部成为 BFC,这样在计算这个盒子高度时,里面的浮动元素也会参与计算:
.container {
width: 200px;
border: solid;
overflow: hidden;
.float {
width: 100px;
height: 100px;
border: solid;
float: left;
}
}
BFC 盒子不会忽视前面的浮动元素
<div class='float'>我是一个左浮动盒子</div>
<div class='block'>
我是块级盒子我是块级盒子我是块级盒子我是块级盒子我是块级盒子我是块级盒子我是块级盒子我是块级盒子我是块级盒子我是块级盒子
</div>
.float {
width: 100px;
height: 100px;
background: skyblue;
float: left;
}
.block {
width: 200px;
background: green;
}
可以看见,后面的 block 盒子忽视掉了其前面的浮动盒子,浮动盒子覆盖在了它的上面(文本不会忽视),此时我们让 block 盒子内部生成 BFC,那么 block 就能感知浮动盒子的存在了:
.block {
width: 200px;
background: green;
overflow: hidden;
}
BFC 盒子避免垂直方向 margin 塌陷(重叠)
只有当两个块级盒子(block)在同一个 BFC 中,才会出现垂直方向上的 margin 重叠,所以思路就是为其中一个盒子外部嵌套一个新盒子,然后使用这个新盒子创建一个新的 BFC 就行了:
<div class='div1'>1</div>
<div class='div2-container'>
<div class='div2'>2</div>
</div>
.div1, .div2 {
width: 100px;
height: 100px;
border: solid;
}
.div1 {
margin-bottom: 30px;
}
.div2 {
margin-top: 30px;
&-container {
overflow: hidden;
}
}
这样就不会发生垂直方向的 margin 重叠现象了: