BFC是什么?

前言

对于BFC的概念以及应用场景一直都不是很明白,今天着重去了解了一下,做了以下总结。

BFC的定义

在解释 BFC 是什么之前,需要先介绍 Box、Formatting Context的概念。

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; run-in box: css3
中才有, 这儿先不讲了。

Formatting context

  Formatting context 是 W3C CSS2.1
规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。最常见的
Formatting context 有 Block fomatting context (简称BFC)和 Inline
formatting context (简称IFC)。 CSS2.1 中只有 BFC 和 IFC, CSS3 中还增加了
GFC 和 FFC。

BFC

  BFC(Block Formatting Context)直译为”块级格式化范围”。是 W3C CSS 2.1
规范中的一个概念,它决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用
当涉及到可视化布局的时候,Block Formatting
Context提供了一个环境,HTML元素在这个环境中按照一定规则进行布局。一个环境中的元素不会影响到其它环境中的布局。比如浮动元素会形成BFC,浮动元素内部子元素的主要受该浮动元素影响,两个浮动元素之间是互不影响的。这里有点类似一个BFC就是一个独立的行政单位的意思。
也可以说BFC就是一个作用范围。可以把它理解成是一个独立的容器,并且这个容器的里box的布局,与这个容器外的毫不相干

怎样才能形成BFC

  1. float的值不能为none

  2. overflow的值不能为visible

  3. display的值为table-cell, table-caption, inline-block中的任何一个

  4. position的值不为relative和static

BFC的约束规则

  1. 内部的Box会在垂直方向上一个接一个的放置

  2. 垂直方向的距离有margin决定(属于同一个BFC的两个相邻Box的margin会发生重叠,与方向无关)

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

  4. BFC的区域不会与float的元素区域重叠

  5. 计算BFC的高度时,浮动子元素也参与计算

  6. BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面元素,反之亦然

看到以上的几条约束,让我想起学习css时的几条规则

Block元素会扩展到与父元素同宽,所以block元素会垂直排列
垂直方向上的两个相邻DIV的margin会重叠,而水平方向不会(此规则并不完全正确)
浮动元素会尽量接近往左上方(或右上方)
为父元素设置overflow:hidden或浮动父元素,则会包含浮动元素

BFC的作用

1. 不和浮动元素重叠

如果一个浮动元素后面跟着一个非浮动的元素,那么就会产生一个覆盖的现象,很多自适应的两栏布局就是这么做的。比如下图的效果,参考例子

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
28
29
30
31
32
33
34
35
36
37
38
39
<style>

body {

width: 300px;

position: relative;

}

.aside {

width: 100px;

height: 150px;

float: left;

background: #f66;

}

.main {

height: 200px;

background: #fcc;

}

</style>

<body>

<div class="aside"></div>

<div class="main"></div>

</body>

案例分析:
很明显,.aside和.mian重叠了。试分析一下,由于两个box都处在同一个BFC中,都是以BFC边界为起点,如果两个box本身都具备BFC的话,会按顺序一个一个排列布局,现在.main并不具备BFC,根据BFC布局规则第3条

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

虽然存在浮动的元素aslide,但main的左边依然会与包含块的左边相接触
根据BFC布局规则第四条:

BFC的区域不会与float box重叠

我们可以通过触发main生成BFC, 来实现自适应两栏布局

1
2
3
4
5
.main {

overflow: hidden;

}

复制代码

当触发main生成BFC后,这个新的BFC不会与浮动的aside重叠。因此会根据包含块的宽度,和aside的宽度,自动变窄。效果如下:

2. 清除元素内部浮动

案例代码:

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
28
29
30
31
32
33
34
35
<style>

.par {

border: 5px solid #fcc;

width: 300px;

}

.child {

border: 5px solid #f66;

width:100px;

height: 100px;

float: left;

}

</style>

<body>

<div class="par">

<div class="child"></div>

<div class="child"></div>

</div>

</body>

复制代码

根据BFC布局规则第六条:

计算BFC的高度时,浮动元素也参与计算

为达到清除内部浮动,我们可以触发par生成BFC,那么par在计算高度时,par内部的浮动元素child也会参与计算。

1
2
3
4
5
.par{

overflow:hidden

}

复制代码

加入上面样式,即可解决问题,效果如下:

3. 防止垂直 margin 重叠
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
<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>

复制代码

页面如下:

两个p之间的距离为100px,发送了margin重叠。根据BFC布局规则第二条:

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

我们可以在p外面包裹一层容器,并触发该容器生成一个BFC。那么两个P便不属于同一个BFC,就不会发生margin重叠了。

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
28
29
30
31
32
33
34
35
36
37
<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时,两个元素才有可能发生垂直Margin的重叠,这个包括相邻元素,嵌套元素,只要他们之间没有阻挡(例如边框,非空内容,padding等)就会发生margin重叠。
因此要解决margin重叠问题,只要让它们不在同一个BFC就行了,但是对于两个相邻元素来说,意义不大,没有必要给它们加个外壳,但是对于嵌套元素来说就很有必要了,只要把父元素设为BFC就可以了。这样子元素的margin就不会和父元素的margin发生重叠了。

作者:没有昵称cpp
链接:https://juejin.cn/post/6844903544726749198
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!