在讲BFC之前我们需要先来说说Formatting Context
1. Formatting Context
1.1 什么是Formatting Context
Formatting Context
(格式化上下文):是W3C CSS2.1规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系、相互之间的作用。
一个格式化的内容是在其中一组相关的盒中规定的环境。不同的格式化上下文根据不同的规则布置它们的框。例如flex
格式上下文根据flex
布局规则布置相应的框。
当一个框建立一个独立的格式化上下文(无论该格式化上下文是否与其父级相同类型),它本质上创建了一个新的、独立的布局环境:除了通过框本身的大小调整外,其后代的布局是(通常)不受框外格式化上下文的规则和内容的影响。
1.2 常见类型
到目前css3为止,css渲染规则有四种常见类型:
● BFC-块级格式化上下文(Block Formatting Context)
● IFC-行内格式化上下文(Inline Formatting Context)
● FFC-弹性格式化上下文(Flex Formatting Context)
● GFC-网格布局格式化上下文(GridLayout Formatting Context)
2. 什么是BFC
块格式化上下文(Block Formatting Context,BFC)是web页面的可视css渲染的一部分,是块盒子的布局过程发生的区域。
简单的说,BFC就是一个建立了新的块格式化上下文的块容器中的渲染区域。是一个可用来维护内部浮动、排除外部浮动和抑制边距折叠的框。
3. 怎么创建一个BFC
下列方式会创建块格式化上下文:
● 根元素()
● 浮动元素(元素的float不是none)
● 绝对定位元素(元素的position为absolute或fixed)
● 行内块元素(元素的display为inline-block)
● 表格单元格(元素的display为table-cell,HTML表格单元格默认为该值)
● 表格标题(元素的display为table-caption,HTML表格标题默认为该值)
● 匿名表格单元格元素(元素的display为table、table-row、table-row-group、table-header-group、table-footer-group(分别是HTML table、row、tbody、thead、tfoot的默认属性)或inline-table)
● overflow计算值不为visible的块元素
● display至为flow-root的元素
● contain值为layout、content或paint的元素https://developer.mozilla.org/zh-CN/docs/Web/CSS/contain
● 弹性元素(display为flex或inline-flex元素的直接子元素)
● 网格元素(display为grid或inline-grid元素的直接子元素)
● 多列容器(元素的column-count或column-width不为auto,包括column-count为1)
● column-span为all的元素始终会创建一个新的BFC,即使该元素没有包裹在一个多列容器中
一句话总结:浮动、绝对定位元素、不是块框的块容器(例如内联块、表格单元格和表格标题),以及“溢出”不是“可见”的块框,为其内容建立新的块格式上下文。
块格式化上下文对浮动定位与清除浮动都很重要。浮动定位和清楚浮动时只会应用于同一个BFC
内的元素。浮动不会影响其他BFC
中元素的布局,而清除浮动只能清除同一BFC
中在它前面元素的浮动。外边距折叠也只会发生在属于同一BFC
的块级元素之间。
4. BFC的约束规则
https://www.w3.org/TR/CSS2/visuren.html#block-formatting
可以归纳为:
- 内部的盒会在垂直方向一个接一个排列
- 两个同级盒之间的垂直距离由margin属性决定。同一个块格式上下文中相邻块级盒之间的垂直边距折叠。
- 每个盒的左外边缘接触包含块的左边缘(对于从右到左的格式,右边缘接触),除非盒建立了新的块格式化上下文。
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,容器外的元素同样不会影响到里面的元素
- 计算BFC的高度时,考虑BFC所包含的所有元素,连浮动元素也参与计算
- float的元素区域不会覆盖其他BFC的区域
4.1 内部的盒会在垂直方向排列
处于内部的盒会在垂直方向一个接一个的排列。在一个BFC中,块盒与行盒(行盒由一行中所有的内联元素所组成)都会垂直的沿着其父元素的边框排列。
<div class="blue"></div>
<div class="red"></div>
.blue {
background: blue;
width: 100px;
height: 50px;
}
.red {
background: red;
height: 50px;
}
我们可以看到行内块与其他块之间会有间隙,这主要是由换行符空格间隙问题引起的。
display:inline-block元素之间空隙的产生原因和解决方法
4.2 同一个BFC中,会发生边距折叠
两个同级盒之间的垂直距离由margin属性决定。同一个块格式上下文中相邻块级盒之间的垂直边距折叠。
<div class="blue"></div>
<div class="red"></div>
.blue,
.red {
height: 50px;
margin: 40px 0;
}
.blue {
background: blue;
width: 100px;
}
.red {
background: red;
}
4.3 每个元素的左外边距与包含块的左边界相接触
每个盒的左外边缘接触包含块的左边缘(对于从右到左的格式,右边缘接触)。除非盒建立了新的块格式化上下文。
4.4 是页面上的一个隔离的独立容器
BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,容器外的元素同样不会影响到里面的元素
<div class="main">
<div class="child">ABC</div>
</div>
<div class="wrap"></div>
.wrap {
height: 200px;
background: #aaa;
}
.main {
height: 100px;
background: #f66;
}
.child {
width: 200px;
height: 50px;
margin-top: 40px;
background-color: dodgerblue;
}
这个问题发生的原因是根据规范,一个盒子如果没有上补白(padding-top
)和上边框(border-top
),那么这个盒子的上边距会和其内部文档流中的第一个子元素的上边距重叠。
.main {
overflow: hidden;
/*display: inline-block;*/
/*float: left;*/
height: 100px;
background: #.main {
overflow: hidden;
/*display: inline-block;*/
/*float: left;*/
height: 100px;
background: #f66;
}
}
4.5 计算BFC的高度时,考虑BFC所包含的所有元素,连浮动元素也参与计算
<div class="out">
<div class="float"></div>
<div class="no-float"></div>
</div>
.out {
width: 100%;
background-color: rgb(113, 112, 112);
}
.float {
float: right;
width: 200px;
height: 200px;
background-color: dodgerblue;
}
.no-float {
/* overflow: hidden; */
width: 200px;
height: 100px;
background-color: darkorange;
}
从上面的例子里我们可以看到,在一个普通的块元素中,如果不设置其高度,其高度会根据该块子元素高度进行高度计算。但并不计算其子元素中的浮动元素的高度。当我们把外部块元素设置为可创建bfc
的元素,其子元素中的浮动元素会参与计算块高度。
.out {
overflow: hidden;
/* display: inline-block; */
/* position: absolute; */
/* float: left; */
width: 100%;
background-color: rgb(113, 112, 112);
}
4.6 float的元素区域不会覆盖其他BFC的区域
<div class="out">
<div class="float"></div>
<div class="no-float"></div>
</div>
.out {
width: 400px;
height: 200px;
background-color: rgb(113, 112, 112);
}
.float {
float: left;
width: 50px;
height: 50px;
background-color: dodgerblue;
}
.no-float {
width: 200px;
height: 100px;
background-color: darkorange;
}
我们可以看到浮动元素在未浮动元素之前,因为浮动元素脱离文档流,未浮动元素会侵占浮动元素的位置,出现浮动元素覆盖的情况。我们可以通过使未浮动元素创建一个新的bfc
,达到清除浮动的效果。使用新的bfc
清除浮动只能清除同一BFC
中在它前面的元素的浮动。
.no-float {
display: inline-block;
/* overflow: hidden; */
width: 200px;
height: 100px;
background-color: darkorange;
}
5. BFC的应用场景
5.1 解决外边距塌陷问题
<div class="blue"></div>
<div class="red"></div>
.blue,
.red {
height: 50px;
margin: 40px 0;
}
.blue {
background: blue;
width: 100px;
}
.red {
background: red;
}
该怎么解决外边距塌陷问题?
内层块元素的margin会和其父元素的相邻元素的margin重叠吗?为什么?
<div class="blue">
<div class="blue-inner"></div>
</div>
<div class="red"></div>
.blue-inner,
.red {
height: 50px;
margin: 40px 0;
}
.blue {
background: blue;
}
.red {
background: red;
}
.blue-inner {
width: 100px;
background-color: burlywood;
}
5.2 清除浮动
<div class="float"></div>
<div class="no-float"></div>
.float {
float: right;
width: 50px;
height: 100px;
background-color: dodgerblue;
}
.no-float {
overflow: hidden;
height: 150px;
background-color: darkorange;
}
5.3 解决浮动元素父元素高度塌陷问题
<div class="out">
<div class="float"></div>
<div class="no-float"></div>
</div>
.out {
background-color: wheat;
}
.float {
float: right;
width: 50px;
height: 100px;
background-color: dodgerblue;
}
.no-float {
height: 50px;
background-color: darkorange;
}
.out {
overflow: hidden;
background-color: wheat;
}