一、BFC是什么鬼?

相信做前端开发的人应该都听过BFC这个名词,起初,我也是在网上搜索资料时,看见过它,才去了解它,网上也有很多关于它的资料。
那么到底什么是BFC呢?
BFC(block formatting context)直译为“块格式化上下文”,是页面 CSS 视觉渲染这个过程中的一个概念。它是决定块盒子的布局及浮动元素相互影响的一个因素。
BFC是 W3C CSS 2.1 规范中的一个概念,它是一个独立的渲染区域,只有块级盒(block-level box)参与,它规定了内部的块级盒如何布局,并且与这个区域外部毫不相干。就个人简单理解来说就是,BFC这家伙可以将其下的盒子与外界隔离起来的,让它的子元素在里面玩耍,不会影响到外面的元素。更多具体的内容,大家可以网上自查资料。
二、触发BFC的情况,常见如下:

    1、根元素或其它包含它的元素。

    2、浮动元素(元素的 float 不为 none)

    3、绝对定位元素 (元素的 position 为 absolutefixed)

    4、display的值为table-cell, table-caption, inline-block、display: flex inline-flex的元素。

    5、overflow的值为auto,scrollhidden的元素

三、BFC的布局规则

   1、在BFC中,其内部子元素从包含块顶部开始,按文档流垂直地一个接一个地排列。

   2、相邻的两个元素之间的垂直距离由margin决定,属于同一个BFC的两个相邻块级盒的垂直margin会发生重叠。

   3、在BFC中,每一个内部元素都会从包含块的左边界开始(对于从右向左的排版,则相反), 即使在有浮动元素参与的情况下也是如此(尽管一个元素的内容区域会由于浮动而压缩),除非这个元素也创建了一个新的BFC(在某些情况下这个元素自身会因为floats而变窄)。

    4、BFC的区域不会与float块级盒重叠。

    5、BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。

    6、在计算生成了BFC的元素的高度时,其浮动元素也参与计算。   

也就是,当一个HTML元素满足上面条件的任何一条,都可以产生BFC。

四、关于BFC布局规则的原理说明和作用

下面通过简单的例子说明一下关于上面6条BFC布局的规则和作用。

1、在BFC中,其内部子元素从包含块顶部开始,按文档流垂直地一个接一个地排列。
关于这一条大家应该很好理解,下面先看代码例子:(例子中部分css直接写在style,代码不做优化)

<style type="text/css">
    .box{width: 100px; height: 50px; line-height:50px; text-align: center; color: #fff;}
    .div0{background: #3ABF9A;}
    .div1{background: #3E3434;}
    .div2{background: #00BCD4;}
</style>
<div class="box div0">50px</div>
<div class="box div1">50px</div>
<div class="box div2">50px</div>
50px
50px
50px

从上图中可知,这个三个div是从包含块顶部开始,在垂直方向上,从上到下,一个接一个的排列的。而这里的包含块元素是body。根据第三条,每一个内部元素都会从包含块的左边界开始。

2、两个相邻的元素之间的垂直距离由margin决定,属于同一个BFC的两个相邻Box的margin会发生重叠。
在上面的例子中,我们给三个div加边距看看。如下代码:

<div class="box div0" style="margin-bottom: 50px;">50px</div>
<div class="box div1" style="margin: 50px 0 50px 0;">50px</div>
<div class="box div2" style="margin-top: 50px;">50px</div>
50px
50px
50px

从图中可知,他们的边距发生的了重叠,第一个margin-bottom:50px和第二个margin-top:50px发生重叠了变为50px了,第三个和第二个也是如此。

当我们在第二个div外面包一个div时,使其触发BFC,那么它里面的div和外面的2个div便不属于同一个BFC,就不会发生重叠了。如下所示:

<div class="box div0" style=" margin-bottom: 50px;">50px</div>
<div style="overflow: hidden;">
    <div class="box div1" style="margin: 50px 0 50px 0;">50px</div>
</div>
<div class="box div2" style="margin-top: 50px;">50px</div>
50px
50px
50px

从图中可知,他们的边距不重叠了,垂直方向的间距变为100px了。如我们上面说的“BFC容器里面的子元素不会影响到外面的元素”。它的作用就是可以解决我们平时所说的垂直边距重叠的问题了。

4、在BFC中,每一个内部元素都会从包含块的左边界开始(对于从右向左的排版,则相反), 即使在有浮动元素参与的情况下也是如此(尽管一个元素的内容区域会由于浮动而压缩),除非这个元素也创建了一个新的BFC(在某些情况下这个元素自身会因为floats而变窄)。看如下代码:

<style type="text/css">
    .div0{width:400px; height: 200px;}
    .div1{width: 100px; height: 50px; background: #3ABF9A; float: left;}
    .div2{width: 300px; height: 200px; background: #3E3434;}
</style>
<div class="div0">
    <div class="div1"></div>
    <div class="div2"></div>
</div>

从图中可知,div1元素虽然设置了浮动,但div2的左边依然是从包含块的左边界开始,div1和div2发生了重叠。符合我们上面所说的(即使在有浮动元素参与的情况下也是如此)。

 5、BFC的区域不会与float块级盒重叠

有时候一个浮动元素后面跟着一个非浮动的元素,就会产生一个覆盖的现象,这时候非浮动的元素触发BFC就可以解决这个覆盖的现象了。
我们把上面的例子改改一下,使div2也触发BFC,div2会根据包含块的宽度,和div1的宽度,自动变窄了,自适应宽度,这时div1和div2就不重叠了,也就是说BFC的区域不会与float块级盒重叠了。如下所示:

<style type="text/css">
    .div0{width:400px; height: 200px;}
    .div1{width: 100px; height: 50px; background: #3ABF9A; float: left;}
    .div2{width: 300px; height: 200px; background: #3E3434; overflow: hidden}
</style>
<div class="div0">
    <div class="div1"></div>
    <div class="div2"></div>
</div>

这也是我们平时常用来做两列自适应布局的方法(左边元素浮动,右边元素overflow: hidden触发BFC)。更多内容可以查看:

CSS深入理解流体特性和BFC特性下多栏自适应布局

6、在计算生成了BFC的元素的高度时,其浮动元素也参与计算。 

<style type="text/css">
    .div0{width:400px; border:5px solid #ccc}
    .div1{width: 100px; height: 200px; background: #3ABF9A; float: left;}
    .div2{width: 200px; height: 100px; background: #3E3434; float: left;}
</style>
<div class="div0">
    <div class="div1"></div>
    <div class="div2"></div>
</div> 






如上面代码所示,外部div0元素没有设置高度,其子元素使用浮动的时候,可以才看出两个div已经脱离了父元素的包含块,外围div0并没有自适应撑开高度(灰色部分)
这时,我们可以闭合浮动,触发父元素的BFC,让父元素包含两个子元素,其实,当我们给div0加overflow: hidden触发BFC时,在计算高度时,两个浮动子元素就会参与。如下所示:


<style type="text/css">
    .div0{width:400px; background: #ddd; overflow: hidden}
    .div1{width: 100px; height: 200px; background: #3ABF9A; float: left;}
    .div2{width: 200px; height: 100px; background: #3E3434; float: left;}
</style>
<div class="div0">
    <div class="div1"></div>
    <div class="div2"></div>
</div> 

五、小结:

关于BFC,简单来说,BFC其实就是一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,既然这样,那么那些场景常用到BFC,常用有三个如下:

1、解决垂直边距重叠的问题

2、布局,比如两列自适应布局

3、可以用于清除浮动,计算BFC高度

以上是个人整理的关于理解BFC特性原理的一些简单笔记,如有错误,欢迎指正!

参考:

什么是BFC

块格式化上下文

BFC 、IFC

BFC 神奇背后的原理