CSS-009-BFC

BFC

Block Formatting Context

块格式化上下文

CSS规范中对 BFC 的描述

9.4.1 块格式化上下文

浮动,绝对定位元素,非块盒的块容器(例如,inline-blocks,table-cells和table-captions)和’overflow’不为’visible’的块盒会为它们的内容建立一个新的块格式化上下文

在一个块格式化上下文中,盒在竖直方向一个接一个地放置,从包含块的顶部开始。两个兄弟盒之间的竖直距离由’margin’属性决定。同一个块格式化上下文中的相邻块级盒之间的竖直margin会合并

在一个块格式化上下文中,每个盒的left外边(left outer edge)挨着包含块的left边(对于从右向左的格式化,right边挨着)。即使存在浮动(尽管一个盒的行盒可能会因为浮动收缩),这也成立。除非该盒建立了一个新的块格式化上下文(这种情况下,该盒自身可能会因为浮动变窄)

MDN 对 BFC 的描述

一个块格式化上下文(block formatting context) 是Web页面的可视化CSS渲染出的一部分。它是块级盒布局出现的区域,也是浮动层元素进行交互的区域。

一个块格式化上下文由以下之一创建:

  • 根元素或其它包含它的元素
  • 浮动元素 (元素的 float 不是 none)
  • 绝对定位元素 (元素具有 position 为 absolute 或 fixed)
  • 内联块 (元素具有 display: inline-block)
  • 表格单元格 (元素具有 display: table-cell,HTML表格单元格默认属性)
  • 表格标题 (元素具有 display: table-caption, HTML表格标题默认属性)
  • 具有overflow 且值不是 visible 的块元素,
  • display: flow-root 触发BFC
  • column-span: all 应当总是会创建一个新的格式化上下文,即便具有 column-span: all 的元素并不被包裹在一个多列容器中。

一个块格式化上下文包括创建它的元素内部所有内容,除了被包含于创建新的块级格式化上下文的后代元素内的元素。

块格式化上下文对于定位 (参见 float) 与清除浮动 (参见 clear) 很重要。定位和清除浮动的样式规则只适用于处于同一块格式化上下文内的元素。浮动不会影响其它块格式化上下文中元素的布局,并且清除浮动只能清除同一块格式化上下文中在它前面的元素的浮动。

张鑫旭对 BFC 的描述

http://www.zhangxinxu.com/wordpress/2015/02/css-deep-understand-flow-bfc-column-two-auto-layout/

BFC全称”Block Formatting Context”, 中文为“块级格式化上下文”。啪啦啪啦特性什么的,一言难尽,大家可以自行去查找,我这里不详述,免得乱了主次,总之,记住这么一句话:BFC元素特性表现原则就是,内部子元素再怎么翻江倒海,翻云覆雨都不会影响外部的元素。所以,避免margin穿透啊,清除浮动什么的也好理解了。

BFC 到底是什么?

先思考一个问题:

请问:什么是色情?

联邦最高法院大法官斯图尔特更有一句名言

我不知道什么是色情,不过,我看了之后,就能知道

I know it when I see it

类似地:

1、我不知道什么是 BFC
2、但是你写出样式,我就知道这是不是 BFC

BFC 就是这样的东西(堆叠上下文也是)

1、它没有定义
2、它只有特性/功能

功能1:爸爸管儿子

用 BFC 包住浮动元素。(这不是清除浮动,.clearfix 才是清除浮动)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html>
<head>
<style>
.baba{
border: 10px solid red;
min-height: 10px;
display: flow-root; /*触发BFC*/
}
.erzi{
background: green;
float:left; /* 浮动就会脱离文档流 ,导致 baba 的高度塌陷 */
width: 300px;
height: 100px;
}
</style>
</head>
<body>
<div class="baba">
<div class="erzi"></div>
</div>
</body>
</html>

如何触发BFC

  • 父级 浮动、定位、或者 display = inline-block\table-cell\table-caption 或者 display不是block的值的容器、 overflow 不为 visible的
    • overflow:auto
    • overflow:hidden 会引发副作用,如果内部元素,超出内容不会显示
    • display:inline-block
    • display:table-cell
    • display:flow-root 让当前元素触发BFC,CSS3新出的属性,兼容性不太好

解释BFC内部元素 margin融合问题

  • 如果两个div没有浮动,它们在一个div中,它们的竖直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
<!DOCTYPE html>
<html>
<head>
<style>
.baba{
border: 10px solid red;
min-height: 10px;
display: flow-root; /*触发BFC*/
}
.erzi{
background: green;
width: 400px;
height: 100px;
margin:10px;
}
</style>
</head>
<body>
<div class="baba">
<div class="erzi"></div>
<div class="erzi"></div>
</div>
</body>
</html>

一个BFC包含它的元素内的所有内容,如果它的孩子元素是BFC,那么这个孩子的后代元素是不会被包含进来的

通俗理解

  • baba是BFC
  • erzi是 baba的子元素,同时也是BFC
  • sunzi 是 erzi的子元素,它的内容就不会被 baba包含
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
<!DOCTYPE html>
<html>
<head>
<style>
.baba{
border: 10px solid red;
width:500px;
min-height: 10px;
display:flow-root;
}
.erzi{
background: green;
width: 400px;
height: 100px;
margin:10px;
float:left; /* 触发BFC */
margin-top:100px; /* 由于父级 触发BFC所以 这个距离会被包含进 baba里*/
}
.sunzi{
height: 50px;
width: 400px;
margin-top:200px; /* 由于 sunzi被 BFC元素 erzi罩着, 所以无法被包含进 baba内 */
background:blue;
/* 由于 erzi在带sunzi,所以baba 就不管这个sunzi了 */
}
</style>
</head>
<body>
<div class="baba">
<div class="erzi">
<div class="sunzi"></div>
</div>
</div>
</body>
</html>

功能2:兄弟之间划清界限

用 float + div 做左右自适应布局

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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
<style>
.gege{
width: 100px;
min-height: 600px;
border: 3px solid red;
float: left;
margin-right: 20px;
}

.didi{
min-height: 600px;
border: 5px solid green;
overflow:auto;
/* display:flow-root; */
}
</style>
</head>
<body>
<div class="gege">gege</div>
<div class="didi">1234</div>
</body>
</html>
  • 第一个方式就是 overflow:auto
  • 第二个方式就是 display:flow-root;

如何回答面试官

千万别解释什么是 BFC,一解释就错
用上面的例子回答什么是 BFC

常见问题

BFC和文档流有什么关系

  • BFC说的是一个div有一些属性后(float:left 或position:absolute)它自己就是BFC。BFC说的是这个 div 的特性,说的是这个div会包住它里面,它里面的内容是不会变得
  • 文档流是 内联元素从左到右,块级元素从上到下排列
  • BFC影响一个元素的宽高,文档流影响是排列顺序

BFC使用场景

  • 爸爸管儿子(参考上面的功能1),注意这不是清除浮动,这是BFC让爸爸管儿子
    • BFC可以模拟清除浮动的效果,但是我可以直接 clearfix,那么BFC就没意义了,BFC会导致副作用 如 overflow:hidden;的时候,但是clearfix不会有副作用,除非所有浏览器都支持display:flow-root
    • 不要用BFC清除浮动
  • 兄弟之间划清界限(参考上面的功能2)
    • 也就是以前的左右布局
    • 同样也可以不用它,用flex解决这些问题
    • BFC是时代的产物

margin穿透

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html>
<head>
<style>
.baba{
background:red;
}
.erzi{
height: 100px;
margin-top:100px;
background:green;
}
</style>
</head>
<body>
<div class="baba">
<div class="erzi"></div>
</div>
</body>
</html>
  • 现在 erzi 的 margin会穿过 baba
  • 给 baba 添加 overflow:hidden 就能触发BFC,不让 erzi穿出来,但是有副作用就是 erzi内如果有定位元素超出容易会被隐藏
  • 所以 你只能给 baba 加 display:flow-root 或者 borer

什么情况下一定要BFC呢?

没有任何情况一定要BFC,所有的场景都可以不用BFC实现

面试一定要搞懂BFC