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
。