什么是FC
在说BFC之前我们先说一下什么是FC,FC的全称是Formatting Context(格式化上下文),元素在标准流里面都是属于一个FC的。
在标准流中一个元素要么属于块级格式化上下文(BFC),要么属于行内级格式化上下文(IFC),而一个块级元素是属于块级格式化上下文(BFC)的。行内级元素则是属于行内级格式化上下文(IFC)的。
哪些情况下会创建BFC
(1)根元素 < html >
(2)浮动元素(元素的 float 不是 none)
(3)绝对定位元素(元素的 position 为 absolute 或 fixed)
(4)行内块元素(元素的 display 为 inline-block)
(5)表格单元格(元素的 display 为 table-cell,HTML表格单元格默认为该值),表格标题(元素的 display 为 table-caption,HTML表格标题默认为该值)
(6)匿名表格单元格元素(元素的 display 为 table、table-row、 table-row-group、table-header-group、table-footer-group(分别是HTML table、row、tbody、thead、tfoot 的默认属性)或 inline-table
(7)overflow的值不为 visible 的块元素
(8)弹性元素(display 为 flex 或 inline-flex 元素的直接子元素)
(9)网格元素(display 为 grid 或 inline-grid 元素的直接子元素)
(10)display 值为 flow-root 的元素
BFC怎样作用于元素
(1)在一个块级格式化上下文中,盒子在垂直方向上一个挨着一个排布。
(2)两个相邻盒子之间的垂直距离由margin决定
(3)在一个块级格式化上下文中相邻两个盒子之间的垂直margin会进行合并
(4)在一个BFC中,每个元素的左边缘是紧挨着包含块的左边缘
BFC的作用
(一) 解决折叠问题
我们来看以下一段代码的表现:
很明显2个div的上下margin被折叠了。怎么解决这个问题呢? 我们注意到,上面的第3点说,在一个块级格式化上下文中相邻两个盒子之间的垂直margin会进行合并,如果我们让2个盒子不在同一个BFC中,这个问题不就解决了吗?然后我们再看看可以创建BFC的10种情况,我们利用overflow的值不为 visible 的块元素可以创建一个BFC这一条,分别给2个块级元素加上overflow:auto属性。如下:
但是,我们仍然可以看到,问题并没有解决,导致这个问题的原因在于,box1和box2虽然自身都创建了一个BFC,但是他们自身仍然处于同一个BFC中,这个BFC就是html元素了。要解决这个问题,是让box1和box2处于不同的BFC中。我们给box1套一个外层的div,然后给这个div的overflow属性设置为auto。让box1处在container块的BFC中,而box2仍然处于html的BFC中,这样,问题就可以得到解决了。如下:
(二) 解决浮动的高度坍塌问题
我们来看一下下面的代码:
在浏览器显示的结果如下:
可以看到,我们虽然给包含块container设置了背景,但是包含块并没有高度,也就是高度坍塌了,出现这个问题的原因是浮动元素不会向父级元素汇报自身高度。
解决浮动元素高度坍塌问题的方法也很简单,只要让浮动元素的包含块形成一个BFC就可以了,如下:
结果如下: 可以看到包含块有高度了。
为什么让包含块形成一个BFC就可以解决高度坍塌问题呢?
一个高度为auto的块级格式化上下文的高度是这样计算的:
(1)如果这个块只有行内级子元素,那么它的高度是最上面的行盒的顶部和最下面的行盒的底部的距离
(2)如果有块级子元素,那么它的高度是最上面的块级盒子的margin-top边缘和最下面的块级盒子的margin-bottom 边缘之间的距离。
(3)如果有绝对定位子元素将会被忽略,而相对定位的盒子将会被考虑在高度计算之内,但是并不会考虑相对定位盒子的offset值
(4)另外,如果元素有浮动的后代元素,其底部边缘低于元素的底部内容边缘,(包含块)则会增加高度以包含这些边缘。
注意到以上第4点,可以看到是外部形成BFC的包含块主动包裹浮动子块,而不是子块把高度汇报给了包含块。这就是BFC能解决浮动高度坍塌的原因。但是由于形成BFC的包含块高度的计算仍然会忽略绝对定位子元素,所以即使绝对定位子元素的高度坍塌问题同样是由于子元素不向父元素汇报自身高度,但是BFC并不能解决绝对定位元素高度坍塌问题。