前言
BFC是css中的一个重要,也经常会在面试中问到。想当年,小编在面试时被问到BFC也是一脸蒙圈,同时小编有时候也会面试一些其他人,有的甚至没听过这个的概念,也可能在工作中,有的人无意中用到了BFC却不知道它的概念。因此,今天有必要再把这个问题拿出来说一说了。
一、简介
所谓的文档流,就好比如一块块的正方形组成的一个整体,而这些正方形就代表着每个div。当某个div脱离了这个整体,也就代表他脱离了文档流。然后下一个div就会来填补脱离的div的位置。
我们常说的文档流其实分为定位流、浮动流、普通流三种。而普通流其实就是指BFC中的FC。FC(Formatting Context),直译过来是格式化上下文,它是页面中的一块渲染区域,有一套渲染规则,决定了其子元素如何布局,以及和其他元素之间的关系和作用。
普通流
- 在常规流中,盒一个接着一个排列;
- 在块级格式化上下文里面, 它们竖着排列;
- 在行内格式化上下文里面, 它们横着排列;
- 当position为static或relative,并且float为none时会触发常规流;
- 对于静态定位(static positioning),position: static,盒的位置是常规流布局里的位置;
- 对于相对定位(relative positioning),position: relative,盒偏移位置由top、bottom、left、right属性定义。即使有偏移,仍然保留原有的位置,其它常规流不能占用这个位置。
浮动流
- 左浮动元素尽量靠左、靠上,右浮动同理;
- 这导致常规流环绕在它的周边,除非设置 clear 属性;
- 浮动元素不会影响块级元素的布局;
- 但浮动元素会影响行内元素的布局,让其围绕在自己周围,撑大父级元素,从而间接影响块级元素布局;
- 最高点不会超过当前行的最高点、它前面的浮动元素的最高点;
- 不超过它的包含块,除非元素本身已经比包含块更宽;
- 行内元素出现在左浮动元素的右边和右浮动元素的左边,左浮动元素的左边和右浮动元素的右边是不会摆放浮动元素的;
定位流
- 绝对定位方案,盒从常规流中被移除,不影响常规流的布局;
- 它的定位相对于它的包含块,相关CSS属性:top、bottom、left、right;
- 如果元素的属性position为absolute或fixed,它是绝对定位元素;
- 对于position: absolute,元素定位将相对于上级元素中最近的一个relative、fixed、absolute,如果没有则相对于body;
二、BFC的概念
块格式化上下文(Block Formatting Context,BFC) 是Web页面的可视CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。这是MDN上对BFC的解释。
BFC 指一个独立的渲染区域或者说是一个隔离的独立容器。用于决定这块盒子的布局及浮动相互影响范围的一个区域,只有块级元素盒子(Block-level box)参与,它规定了内部的块级元素盒子(Block-level box)如何布局,并且与这个区域外部毫不相干。
注意:
一个BFC的范围包含创建该上下文元素的所有子元素,但不包括创建了新BFC的子元素的内部元素。这从另一方角度说明,一个元素不能同时存在于两个BFC中。因为如果一个元素能够同时处于两个BFC中,那么就意味着这个元素能与两个BFC中的元素发生作用,就违反了BFC的隔离作用。
三、BFC的特征
(1)BFC内部,盒子由上至下按顺序进行排列,其间隙由盒子的外边距决定,并且,当同一个BFC中的两个盒子同时具有相对方向的外边距时,其外边距还会发生叠加(Margin Collapse);
(2)BFC内部,无论是浮动盒子还是普通盒子,其左总是与包含块的左边相接触(从右到左的的格式,否则为与右边框相接触);
(3)BFC 区域不会与float box区域相叠加;
(4)BFC内外布局不会相互影响;
(5)计算BFC高度的时候,浮动元素的高度也计算在内。
四、形成BFC的条件
1.根元素:html;
2. 浮动元素:float除none以外的值;
3. 绝对定位元素:position的值为absolute和fixed;
4. overflow的计算值(Computed)不为 visible 的块元素;
5. contain的值为 layout、content 或 paint 的元素;
6. display的值为:
(1) 行内块元素:inline-block;
(2) 表格单元格:table-cell,HTML表格单元格默认为该值;
(3) 表格标题:table-caption,HTML表格标题默认为该值;
(4) 匿名表格单元格元素:table、table-row、 table-row-group、 table-header-group、table-footer-group(分别是HTML table、row、tbody、thead、tfoot 的默认属性)或 inline-table);
(5) flow-root 的元素;
(6) 弹性元素:flex 或 inline-flex 元素的直接子元素;
(7) 网格元素:grid 或 inline-grid 元素的直接子元素;
7.多列容器:元素的column-count或 column-width (en-US) 不为 auto,包括 column-count 为 1;
8.column-span 为 all 的元素始终会创建一个新的BFC,即使该元素没有包裹在一个多列容器中 。
五、BFC的应用
1.阻止相邻元素的margin合并
BFC内部,盒子由上至下按顺序进行排列,其间隙由盒子的外边距决定,并且,当同一个BFC中的两个盒子同时具有相对方向的外边距时,其外边距还会发生叠加(Margin Collapse)。
<div class="container0">
<div class="box1"></div>
<div class="box2"></div>
</div>
.container0 {
width: 400px;
border: 1px solid red;
}
.container0 .box1 {
height: 60px;
margin: 30px 0;
background-color: red;
}
.container0 .box2 {
height: 60px;
margin: 60px 0;
background-color: red;
}
第一个子盒子有上边距(不会发生margin穿透的问题);两个子盒子的垂直距离为100px而不是150px,因为垂直外边距会折叠,间距以较大的为准。由此可见,box1和box2两个相邻元素的margin发生了合并。
当使用BFC后:
<div class="container1">
<div class="wrapper">
<div class="box1"></div>
</div>
<div class="box2"></div>
</div>
.container1 {
width: 400px;
border: 1px solid red;
}
.container1 .wrapper {
// 使用BFC
overflow: hidden;
}
.container1 .wrapper .box1 {
height: 60px;
margin: 30px 0;
background-color: red;
}
.container1 .box2 {
height: 60px;
margin: 60px 0;
background-color: red;
}
2.BFC区域不会与float box区域相叠加
(1)两栏布局。左边固定宽度,右边不设宽,因此右边的宽度自适应,随浏览器窗口大小的变化而变化。
<div class="container3">
<div class="column"></div>
<div class="column"></div>
</div>
.container3{
overflow: hidden;
}
.container3 .column:nth-of-type(1) {
float: left;
width: 200px;
height: 300px;
margin-right: 10px;
background-color: red;
}
.container3 .column:nth-of-type(2) {
overflow: hidden;/*创建bfc */
height: 300px;
background-color: blue;
}
(2)还有三栏布局。左右两边固定宽度,中间不设宽,因此中间的宽度自适应,随浏览器的大小变化而变化。
<div class="container4">
<div class="column"></div>
<div class="column"></div>
<div class="column"></div>
</div>
.container4 .column:nth-of-type(1),
.container4 .column:nth-of-type(2) {
float: left;
width: 100px;
height: 300px;
background-color: green;
}
.container4 .column:nth-of-type(2) {
float: right;
}
.container4 .column:nth-of-type(3) {
overflow: hidden; /*创建bfc*/
height: 300px;
background-color: red;
}
3.阻止元素被浮动元素覆盖
也可以用来防止字体环绕浮动的盒子会遮盖下面的盒子,但是下面盒子里的文字是不会被遮盖的,文字反而还会环绕浮动的盒子。这也是一个比较有趣的特性。
先来看一个文字环绕效果:
<div class="container5">
<div class="left">我是box1</div>
<p>我是box2,人生得意须尽欢,莫使金樽空对月。天生我材必有用,千金散尽还复来。人生得意须尽欢, 莫使金樽空对月。天生我材必有用,千金散尽还复来。
</div>
.container5 {
overflow: hidden;
width: 300px;
margin: 100px 0;
}
.container5 .left {
float: left;
width: 80px;
height: 80px;
background-color: yellow;
}
.container5 p {
background-color: green;
margin: 0;
padding: 0;
}
在上图中的box2为p元素。正如我们所看到的,这个p元素并没有移动,但是它却出现在浮动元素的下方。p元素的line boxes(指的是文本行)进行了移位。此处line boxes的水平收缩为浮动元素提供了空间。随着文字的增加,因为line boxes不再需要移位,最终将会环绕在浮动元素的下方,因此文字环绕的情况。
这时候其实第二个元素有部分被浮动元素所覆盖,(但是文本信息不会被浮动元素所覆盖) 如果想避免元素被覆盖,可触发第二个元素的 BFC 特性,在第二个元素中加入 overflow: hidden,就会变成:
<div class="container6">
<div class="left">我是box1</div>
<p>我是box2,人生得意须尽欢,莫使金樽空对月。天生我材必有用,千金散尽还复来。人生得意须尽欢, 莫使金樽空对月。天生我材必有用,千金散尽还复来。
</div>
.container6 {
overflow: hidden;
width: 400px;
}
.container6 .left {
float: left;
width: 80px;
height: 80px;
background-color: yellow;
}
.container6 p {
// 触发
overflow: hidden;
background-color: green;
margin: 0;
padding: 0;
}
4.BFC包含浮动的块
BFC可以包含浮动的元素(清除浮动)
<div class="container7">
<div class="box"></div>
</div>
// css
.container {
border: 1px solid red;
}
.container .box {
float: left;
width: 100px;
height: 100px;
background: blue;
}
由于容器内元素浮动脱离文档流,导致容器只剩下2px边距高度。
采用BFC后:
<div class="container7">
<div class="box"></div>
</div>
// css
.container {
// 创建BFC
overflow: hidden;
border: 1px solid red;
}
.container .box {
float: left;
width: 100px;
height: 100px;
background: blue;
}
5.BFC中的盒子对齐
在BFC中,每个盒子的左外边框紧挨着包含块的左边框(从右到左的格式,则为紧挨右边框)。即使存在浮动也是这样的(尽管一个盒子的边框会由于浮动而收缩),除非这个盒子的内部创建了一个新的BFC浮动,盒子本身将会变得更窄)。
<div class="container2">
<div class="box1"></div>
<div class="box2"></div>
<div class="box3"></div>
<div class="box4"></div>
</div>
.container2 {
position: absolute; /* 创建一个BFC环境*/
height: auto;
background-color: #eee;
height: 20px;
}
.container2 .box1 {
width: 300px;
background-color: red;
height: 50px;
}
.container2 .box2 {
width: 400px;
background-color: green;
height: 50px;
}
.container2 .box3 {
float: left;
width: 100px;
background-color: yellow;
height: 25px;
}
.container2 .box4 {
width: 200px;
height: 50px;
background-color: purple;
}
在上图中我们可以看到,BFC内部,无论是浮动盒子还是普通盒子,其左总是与包含块的左边相接触(从右到左的的格式,则为与右边框相接触)。在最后一个盒子里我们可以看到尽管那里有一个浮动元素(黄色)在它的左边,另一个元素(紫色)仍然紧贴着包含块的左边框。
六、总结
写在最后的建议,创建BFC时最好的方法是使用overflow:hidden,因为overflow:hidden对布局的影响最小,只需要注意盒子内内容的高度,避免出现滚动条即可。