Yapei Li

专注于前端领域

0%

BFC

BFC的定义

BFC(Block formatting context)直译为”块级格式化上下文“。

它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。

它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用

FC

formatting context的首字母缩写,直译过来是格式化上下文,它是页面中的一块渲染区域,有一套渲染规则,决定了其子元素如何布局,以及和其他元素之间的关系和作用

常见的FC有BFCIFC(行级格式化上下文),还有GFC(网格布局格式化上下文)和FFC(自适应格式化上下文)

block-level box(块级盒子)

Alt text

盒子是由marginborderpaddingcontent组成的,实际上每种类型的四条边定义了一个盒子,分别是分别是content boxpadding boxborder boxmargin box,这四种类型的盒子一直存在,即使他们的值为0。

决定块盒在包含块中与相邻块盒的垂直间距的便是margin-box

Box之间的距离虽然也可以使用padding来控制,但是此时实际上还是属于box内部里面,而且使用padding来控制的话就不能再使用border属性了。

三种文档流的定位方案(控制元素的布局)

常规流 (normal flow)

在普通流中,元素按照其在 HTML 中的先后位置至上而下布局

也可以说,普通流中元素的位置由该元素在 HTML 文档中的位置决定

  • 在常规流中,盒一个接着一个排列;
  • 在块级格式化上下文里面, 它们竖着排列;块级元素则会被渲染为完整的一个新行,除非另外指定,否则所有元素默认都是普通流定位
  • 在行内格式化上下文里面, 它们横着排列,直到当行被占满然后换行
  • positionstaticrelative,并且floatnone时会触发常规流;
  • 对于静态定位(static positioning),position: static,盒的位置是常规流布局里的位置;
  • 对于相对定位(relative positioning),position: relative,盒偏移位置由top、bottom、left、right属性定义。即使有偏移,仍然保留原有的位置,其它常规流不能占用这个位置。

浮动 (float)

  • 左浮动元素尽量靠左、靠上,右浮动同理
  • 这导致常规流环绕在它的周边,除非设置 clear 属性
  • 浮动元素不会影响块级元素的布局
  • 但浮动元素会影响行内元素的布局,让其围绕在自己周围,撑大父级元素,从而间接影响块级元素布局
  • 最高点不会超过当前行的最高点、它前面的浮动元素的最高点
  • 不超过它的包含块,除非元素本身已经比包含块更宽
  • 行内元素出现在左浮动元素的右边和右浮动元素的左边,左浮动元素的左边和右浮动元素的右边是不会摆放浮动元素的
浮动会造成文本环绕 和 行内元素环绕
1
2
3
4
5
6
7
<div style="border: 2px solid #ccc;">
<div style="width: 100px;height: 100px;float: left;background: red;"></div>
<span>span会环绕红色div</span>
<span>span会环绕红色div</span>
<span>span会环绕红色div</span>
文字也会环绕红色div
</div>

Alt text

1
2
3
4
5
6
<div style="float: left; width: 100px; height: 100px; background: #000;">
</div>
<div style="height: 200px; background: #AAA;">
<div style=" width: 30px; height: 30px; background: red;"></div>
<p>content</p> <p>content</p> <p>content</p> <p>content</p> <p>content</p>
</div>

Alt text

问题:为什么 div 的左上角被覆盖了,而文本却没有被覆盖,float不是应该跟普通流不在一个层级吗?是因为float属性不生效吗?

float的定义和用法:

浮动元素会生成一个块级框,而不论它本身是何种元素

float当初设计的时候就是为了使文本围绕在浮动对象的周围

绝对定位 (absolute positioning)

  • 绝对定位方案,盒从常规流中被移除,不影响常规流的布局;
  • 它的定位相对于它的包含块,相关CSS属性:topbottomleftright
  • 如果元素的属性positionabsolutefixed,它是绝对定位元素;
  • 对于position: absolute,元素定位将相对于上级元素中最近的一个relativefixedabsolute,如果没有则相对于body

触发BFC

  • 【1】根元素,即HTML元素
  • 【2】浮动元素,float的值不为none
  • 【3】overflow的值不为visible (为hiddenautoscroll)
  • 【4】display的值为inline-blocktable-celltable-caption;(与浮动的效果类似)
  • 【5】定位元素,position的值为absolutefixed

display:table也可以生成BFC的原因在于Table会默认生成一个匿名的table-cell,是这个匿名的table-cell生成了BFC

BFC布局规则:

  • 1、内部的Box会在垂直方向,一个接一个地放置。(与常规流中的块级元素及行内元素相同)
  • 2、内部的Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Boxmargin会发生重叠
  • 3、每个元素的margin box的左边, 与包含块(父级块)border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此(这说明BFC中子元素不会超出他的包含块,而position为absolute的元素可以超出他的包含块边界)
  • 4、BFC的区域不会与float box重叠
  • 5、BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
  • 6、计算BFC的高度时,浮动元素也参与计算

Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠

1
2
3
4
5
6
7
8
9
10
11
12
<head>
div{
width: 100px;
height: 100px;
background: lightblue;
margin: 100px;
}
</head>
<body>
<div></div>
<div></div>
</body>

Alt text

因为两个div 元素都处于同一个 BFC 容器下 (这里指 body 元素) 所以第一个 div 的下边距和第二个 div 的上边距发生了重叠,所以两个盒子之间距离只有 100px,而不是 200px

这不是 CSS bug,这是·的一种规范,如果想要避免外边距的重叠,可以将其放在不同的 BFC 容器中(详见 BFC的作用4)。

每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此

1
2
3
4
5
<div class="par">
<div class="child"></div>
<!-- 给这两个子div加浮动,浮动的结果,如果没有清除浮动的话,父div不会将下面两个div包裹,但还是在父div的范围之内。-->
<div class="child"></div>
</div>

左浮是子div的左边接触父div的borderbox的左边,右浮是子div接触父div的borderbox右边,除非设置margin来撑开距离,否则一直是这个规则

BFC的区域不会与float box重叠

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div class="aside"></div>
<div class="text">
<div class="main"></div>
</div>
<!--下面是css代码-->
.aside {
width: 100px;
height: 150px;
float: left;
background: #f66;
}
.main {
height: 200px;
overflow: hidden;//触发main盒子的BFC
background: #fcc;
}
.text{
width: 500px;
}

上面aside盒子有一个浮动属性,覆盖了main盒子的内容,main盒子没有清除aside盒子的浮动。只做了一个动作,就是触发自身的BFC,然后就不再被aside盒子覆盖了。所以:BFC的区域不会与float box重叠。

Alt text

BFC有哪些作用:

  • 1、自适应两栏布局
  • 2、可以阻止元素被浮动元素覆盖
  • 3、可以包含浮动元素——清除内部浮动
  • 4、分属于不同的BFC时可以阻止margin重叠
  • 5、阻止因为浏览器因为四舍五入造成的多列布局换行的情况

自适应两栏布局

BFC的区域不会与float box重叠,因此会根据包含块(父div)的宽度,和aside的宽度,自适应宽度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="aside"></div>
<div class="main"></div>
<!--下面是css代码-->
.aside {
width: 100px;
height: 150px;
float: left;
background: #f66;
}
.main {
height: 200px;
overflow: hidden;//触发main盒子的BFC
background: #fcc;
}

Alt text

分属于不同的BFC时可以阻止margin重叠

1
2
3
4
5
6
<div class="container">
<p></p>
</div>
<div class="container">
<p></p>
</div>
1
2
3
4
5
6
7
8
9
.container {
overflow: hidden;
}
p {
width: 100px;
height: 100px;
background: lightblue;
margin: 100px;
}

这时候,两个盒子边距就变成了 200px

可以包含浮动元素——清除内部浮动

清除浮动原理:触发父divBFC属性,使下面的子div都处在父div的同一个BFC区域之内

阻止因为浏览器因为四舍五入造成的多列布局换行的情况

有时候因为多列布局采用小数点位的width导致因为浏览器因为四舍五入造成的换行的情况,可以在最后一列触发BFC的形式来阻止换行的发生。比如下面栗子的特殊情况

1
2
3
4
5
6
<div class="container">
<div class="column1">column 1</div>
<div class="column2">column 2</div>
<div class="column3">column 3</div>
</div>
<button>TOGGLE BLOCK FORMATTING CONTEXT</button>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.container {
min-height: 200px;
}

.column1,.column2 {
width: 31.3%;
background-color: green;
float: left;
min-height: 100px;
margin: 0 1%;
}

.column3 {
width: 31.3%;
background-color: green;
min-height: 100px;
margin: 0 1%;
}

.bfc {
overflow: hidden;
}


button {
margin-top: 30px;
}
1
2
3
4
5
6
7
8
9
var btn = document.querySelector("button"),
column3 = document.querySelector(".column3");
btn.addEventListener(
"click",
function() {
column3.classList.toggle("bfc");
},
false
);

BFC 与 Layout

IE 作为浏览器中的奇葩,当然不可能按部就班的支持 BFC 标准,于是乎 IE 中有了 Layout 这个东西。

LayoutBFC 基本是等价的,为了处理 IE 的兼容性,在需要触发 BFC 时,我们除了需要用触发条件中的 CSS 属性来触发 BFC

还需要针对 IE 浏览器使用zoom: 1来触发 IE 浏览器的 Layout