BFC的定义
BFC(Block formatting context)直译为”块级格式化上下文“。它是一个独立的渲染区域,只有
Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用
FC
是
formatting context的首字母缩写,直译过来是格式化上下文,它是页面中的一块渲染区域,有一套渲染规则,决定了其子元素如何布局,以及和其他元素之间的关系和作用。常见的FC有
BFC、IFC(行级格式化上下文),还有GFC(网格布局格式化上下文)和FFC(自适应格式化上下文)
block-level box(块级盒子)

盒子是由
margin、border、padding、content组成的,实际上每种类型的四条边定义了一个盒子,分别是分别是content box、padding box、border box、margin box,这四种类型的盒子一直存在,即使他们的值为0。决定块盒在包含块中与相邻块盒的垂直间距的便是
margin-box。
Box之间的距离虽然也可以使用padding来控制,但是此时实际上还是属于box内部里面,而且使用padding来控制的话就不能再使用border属性了。
三种文档流的定位方案(控制元素的布局)
常规流 (normal flow)
在普通流中,元素按照其在
HTML中的先后位置至上而下布局也可以说,普通流中元素的位置由该元素在
HTML 文档中的位置决定
- 在常规流中,盒一个接着一个排列;
- 在块级格式化上下文里面, 它们竖着排列;块级元素则会被渲染为完整的一个新行,除非另外指定,否则所有元素默认都是普通流定位
- 在行内格式化上下文里面, 它们横着排列,直到当行被占满然后换行
- 当
position为static或relative,并且float为none时会触发常规流; - 对于静态定位(
static positioning),position: static,盒的位置是常规流布局里的位置; - 对于相对定位(
relative positioning),position: relative,盒偏移位置由top、bottom、left、right属性定义。即使有偏移,仍然保留原有的位置,其它常规流不能占用这个位置。
浮动 (float)
- 左浮动元素尽量靠左、靠上,右浮动同理
- 这导致常规流环绕在它的周边,除非设置 clear 属性
- 浮动元素不会影响块级元素的布局
- 但浮动元素会
影响行内元素的布局,让其围绕在自己周围,撑大父级元素,从而间接影响块级元素布局 - 最高点不会超过当前行的最高点、它前面的浮动元素的最高点
- 不超过它的包含块,除非元素本身已经比包含块更宽
- 行内元素出现在左浮动元素的右边和右浮动元素的左边,左浮动元素的左边和右浮动元素的右边是不会摆放浮动元素的
浮动会造成文本环绕 和 行内元素环绕
1 | <div style="border: 2px solid #ccc;"> |

1 | <div style="float: left; width: 100px; height: 100px; background: #000;"> |

问题:为什么 div 的左上角被覆盖了,而文本却没有被覆盖,
float不是应该跟普通流不在一个层级吗?是因为float属性不生效吗?
float的定义和用法:
浮动元素会生成一个块级框,而不论它本身是何种元素
float当初设计的时候就是为了使文本围绕在浮动对象的周围。
绝对定位 (absolute positioning)
- 绝对定位方案,盒从常规流中被移除,不影响常规流的布局;
- 它的定位相对于它的包含块,相关CSS属性:
top、bottom、left、right; - 如果元素的属性
position为absolute或fixed,它是绝对定位元素; - 对于
position: absolute,元素定位将相对于上级元素中最近的一个relative、fixed、absolute,如果没有则相对于body;
触发BFC
- 【1】根元素,即
HTML元素 - 【2】浮动元素,
float的值不为none - 【3】
overflow的值不为visible(为hidden、auto、scroll) - 【4】
display的值为inline-block、table-cell、table-caption;(与浮动的效果类似) - 【5】定位元素,
position的值为absolute或fixed
display:table也可以生成BFC的原因在于Table会默认生成一个匿名的table-cell,是这个匿名的table-cell生成了BFC
BFC布局规则:
- 1、内部的
Box会在垂直方向,一个接一个地放置。(与常规流中的块级元素及行内元素相同) - 2、内部的
Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠 - 3、每个元素的
margin box的左边, 与包含块(父级块)border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此(这说明BFC中子元素不会超出他的包含块,而position为absolute的元素可以超出他的包含块边界) - 4、
BFC的区域不会与float box重叠 - 5、
BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。 - 6、计算
BFC的高度时,浮动元素也参与计算
Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
1 | <head> |

因为两个
div元素都处于同一个BFC容器下 (这里指body元素) 所以第一个div的下边距和第二个div的上边距发生了重叠,所以两个盒子之间距离只有100px,而不是200px这不是
CSS的bug,这是·的一种规范,如果想要避免外边距的重叠,可以将其放在不同的 BFC容器中(详见 BFC的作用4)。
每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此
1 | <div class="par"> |
左浮是子div的左边接触父div的borderbox的左边,右浮是子div接触父div的borderbox右边,除非设置margin来撑开距离,否则一直是这个规则
BFC的区域不会与float box重叠
1 | <div class="aside"></div> |
上面
aside盒子有一个浮动属性,覆盖了main盒子的内容,main盒子没有清除aside盒子的浮动。只做了一个动作,就是触发自身的BFC,然后就不再被aside盒子覆盖了。所以:BFC的区域不会与float box重叠。

BFC有哪些作用:
- 1、自适应两栏布局
- 2、可以阻止元素被浮动元素覆盖
- 3、可以包含浮动元素——
清除内部浮动 - 4、分属于不同的
BFC时可以阻止margin重叠 - 5、阻止因为浏览器因为四舍五入造成的多列布局换行的情况
自适应两栏布局
BFC的区域不会与float box重叠,因此会根据包含块(父div)的宽度,和aside的宽度,自适应宽度。
1 | <div class="aside"></div> |

分属于不同的BFC时可以阻止margin重叠
1 | <div class="container"> |
1 | .container { |
这时候,两个盒子边距就变成了
200px
可以包含浮动元素——清除内部浮动
清除浮动原理:触发父
div的BFC属性,使下面的子div都处在父div的同一个BFC区域之内
阻止因为浏览器因为四舍五入造成的多列布局换行的情况
有时候因为多列布局采用
小数点位的width导致因为浏览器因为四舍五入造成的换行的情况,可以在最后一列触发BFC的形式来阻止换行的发生。比如下面栗子的特殊情况
1 | <div class="container"> |
1 | .container { |
1 | var btn = document.querySelector("button"), |
BFC 与 Layout
IE作为浏览器中的奇葩,当然不可能按部就班的支持BFC标准,于是乎IE中有了Layout这个东西。
Layout和BFC基本是等价的,为了处理IE的兼容性,在需要触发BFC时,我们除了需要用触发条件中的CSS属性来触发BFC,还需要针对
IE浏览器使用zoom: 1来触发IE浏览器的Layout。