一、BFC是什么?
它是 Block Formatting Context (块级格式化上下文) 的简称,接下来通过对其中几个名词的解释进一步了解 BFC 定义。
-
Box : CSS布局的基本单位
Box 是 CSS 布局的对象和基本单位, 直观点来说,就是一个页面是由很多个 Box 组成的。元素的类型和display
属性,决定了这个 Box 的类型。不同类型的 Box, 会参与不同的 Formatting Context(一个决定如何渲染文档的容器),因此Box内的元素会以不同的方式渲染。
-
几个常见的盒子:
block-level box:display
属性为block
,list-item
,table
的元素,会生成 block-level box。并且参与 block fomatting context;
inline-level box:display
属性为inline
,inline-block
,inline-table
的元素,会生成 inline-level box。并且参与 inline formatting context;
Formatting context
Formatting context 是指页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。最常见的 Formatting context 有 Block fomatting context (简称 BFC )和 Inline formatting context (简称 IFC )。-
**BFC **:块级格式化上下文
BFC 是指一个独立的块级渲染区域,只有Block-level Box参与,该区域拥有一套渲染规则来约束块级盒子的布局,且与区域外部无关。- BFC就是一种布局方式,可以理解为一个作用范围,即在一个BFC里的布局与其之外的布局不相关或者说不相互影响。
-
举一个形象的例子:
可以把一个页面想象成大的集装箱,这个集装箱里装的货物就是html
元素。在现实生活中为了避免不同人的货物相互混淆,都是把货物打好包装再装入集装箱,这样的话无论你包装里面的货物怎么摆放,都不会影响到其他人的货物。那么这个包装就可以被想象成 Block Formatting Context。
4. 为什么要用BFC?
- 使用一定的CSS声明可以生成BFC,浏览器对生成的BFC有一系列的渲染规则,利用这些渲染规则我们可以达到一定的布局效果,为了达到特定的布局效果我们让元素生成BFC。
二、哪些元素会生成BFC?
当一个HTML元素满足下面条件的任何一点,都可以产生 Block Formatting Context
根元素
float
的值不为none
;overflow
的值不为visible
(可以为hidden
,scroll
,auto
);display
的值为inline-block
,table-cell
,table-caption
,flex
,inline-flex
中的任何一个;position
的值为absolute
,fixed
(不为static
,relative
中的任何一个);display
:table
也认为可以生成BFC,其实这里的主要原因在于table
会默认生成一个匿名的table-cell
,正是这个匿名的table-cell
生成了BFC。常用的用来触发BFC的CSS样式:
overflow: scroll
,overflow: hidden
,display: flex
,float: left
,display: table
其中可能产生的一些问题
display:table
—— 可能会产生一些问题overflow:scroll
—— 可能会显示不必要的滚动条overflow:hidden
—— 将会剪切掉溢出的元素float:left
—— 将会把元素置于容器的左边,其他元素环绕着它
三、BFC的布局规则
- 内部的Box会在垂直方向上一个接一个的放置;
- 垂直方向上的距离有
margin
决定。(完整的说法是:属于同一个BFC的两个相邻的Box的margin
会发生重叠,与方向无关) - 每个盒子的左外边框紧挨着包含块的左边框(从右到左的格式,则为紧挨右边框),即使浮动元素也是如此。(这说明BFC中的子元素不会超出它的包含块)
- BFC的区域不会与
float
的元素区域重叠 - 计算BFC的高度时,浮动子元素也参与计算;
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之亦然;
四、BFC的作用及原理
-
自适应两栏布局
body { width: 300px; }
.aside { width: 100px; height: 150px; float: left; background: #f66; }
.main { height: 200px; background: #fcc; }
<body>
<div class="aside"></div>
<div class="main"></div>
</body>
-
效果图如下:
分析:
根据BFC布局规则 第3条:
* 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反),即使存在浮动也是如此。
现象:虽然存在浮动的元素 aside,但 main 的左边依然会与包含块的左边相接触。
- 修改:
根据BFC布局规则第四条:
* BFC的区域不会与float box重叠。
改变方法:我们可以通过触发 main 生成BFC, 来实现自适应两栏布局,当触发main 生成BFC后,这个新的BFC不会与浮动的 aside 重叠,main 会根据包含块的宽度,和 aside 的宽度,自动变窄。(一个盒子的边框会由于浮动而收缩,盒子本身将会变得更窄)
.main { overflow: hidden;} //或者利用上述其他方式为它生成 BFC
-
新的效果图如下:
-
清除内部浮动
.par { border: 5px solid #fcc; width: 300px; }
.child { border: 5px solid #f66; width: 100px; height: 100px; float: left;}
<body>
<div class="par">
<div class="child"></div>
<div class="child"></div>
</div>
</body>
-
效果图如下:
修改:
根据BFC布局规则第五条:
* 计算BFC的高度时,浮动元素也参与计算
**改变方法:**为达到清除内部浮动,我们可以触发 par 生成BFC,那么 par 在计算高度时,par 内部的浮动元素 child 也会参与计算。
.par { overflow: hidden;} //或者利用上述其他方式为它生成 BFC
-
新的效果图如下:
-
防止垂直 margin 重叠
<style>
p { color: #f55;
background: #fcc;
width: 200px;
line-height: 100px;
text-align: center;
margin: 100px;
}
</style>
<body>
<p>Haha</p>
<p>Hehe</p>
</body>
-
效果图如下:
分析:
根据BFC布局规则第二条:
Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
现象:两个p之间的距离为100px,发送了margin重叠。
- 修改:
我们可以在p外面包裹一层容器,并触发该容器生成一个BFC。那么两个P便不属于同一个BFC,就不会发生margin重叠了。
<style>
.wrap { overflow: hidden; }
p {
color: #f55;
background: #fcc;
width: 200px;
line-height: 100px;
text-align: center;
margin: 100px;
}
</style>
<body>
<p>Haha</p>
<div class="wrap">
<p>Hehe</p>
</div>
</body>
-
新的效果图如下:
其实以上的几个例子都体现了BFC布局规则第六条:
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
解释:
因为BFC内部的元素和外部的元素绝对不会互相影响;
因此,** 当BFC外部存在浮动时,它不应该影响BFC内部Box的布局,BFC会通过变窄,而不与浮动有重叠;
同样的,当BFC内部有浮动时**,为了不影响外部元素的布局,BFC计算高度时会包括浮动的高度;避免margin重叠也是这样的一个道理。
五、详细分析 margin 折叠
1、产生的原因
这些
margin
都处于普通流中,并在同一个BFC中这些
margin
没有被非空内容、padding
、border
或clear
分隔开这些
margin
在垂直方向上是毗邻的-
2、包含的情况:
- 一个box的
margin-top
与第一个子box的margin-top
- 一个box的
margin-bottom
与最后一个子box的margin-bottom
,但须在该box的height:auto
的情况下 - 一个box的
margin-bottom
与紧接着的下一个box的margin-top
- 一个box的
margin-top
与其自身的margin-bottom
,但须满足没创建BFC
注:另一篇CSS盒子对这些情况有图解
- 一个box的
3、折叠边距的计算
当两个margin都是正值的时候,取两者的最大值;
当 margin 都是负值的时候,取的是其中绝对值较大的,然后,从 0 位置,负向位移;
当有正有负的时候,先取出负 margin 中绝对值中最大的,然后,和正 margin 值中最大的 margin 相加。
NOTE:所有毗邻的margin要一起参与运算,不能分步进行。4、举个例子:
1)用 浮动布局 显示成两行两列 ——(为了解决浮动布局里的一个问题:元素浮动不换行怎么办?)
<div id="A">
<div id="red" style="background: red;width: 100px;height: 100px;float: left;">
</div>
<div id="orange" style="background: orange;width: 100px;height: 100px;float: left;">
</div>
</div>
<div id="B">
<div id="yellow" style="background: yellow;width: 100px;height: 100px;float: left;">
</div>
<div id="green" style="background: green;width: 100px;height: 100px;float: left;">
</div>
</div>
我们可以看到四个盒子最终都处在一列里面,为了达到我们的目的,可以**在其中一个外层盒子建立一个BFC**
<div id="A" style="display:inline-block;">
...
</div>
<div id="B">
...
</div>
- 实现多栏布局的一种方式
根据BFC布局规则第四条:
* BFC的区域不会与float box重叠。(与浮动元素相邻的已生成BFC的元素不能与浮动元素互相覆盖)
利用该特性可以作为多栏布局的一种实现方式。
```
<div class="container">
<div class="column">column 1</div>
<div class="column">column 2</div>
<div class="column">column 3</div>
</div>
.column {
width: 31.33%;
background-color: green;
float: left;
margin: 0 1%;
}
.column:last-child
{
float: none;
overflow: hidden;
}
![多列布局.png](http://upload-images.jianshu.io/upload_images/3087126-a263255605a63fa0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
###六、关于BFC的总结
* BFC的几个用途 (但是也有其他方法可以达到这种效果)
* 1、BFC可以阻止垂直边距叠加问题
* 2、BFC可以包含内部元素的浮动
* 3、BFC可以阻止元素被浮动覆盖
* 4、BFC可以决定清除浮动的范围
>参考文章:
[BFC(块级格式化上下文)](http://www.jianshu.com/p/66632298e355)
[我对BFC的理解](http://www.jianshu.com/p/76484dff1cb5)
>其他文章推荐:
[理解CSS中的BFC](http://www.w3cplus.com/css/understanding-block-formatting-contexts-in-css.html)