border-formatting-context

看到一个好玩的,这个东西叫bfc(border-formatting-context),块级格式化上下文。

FC是formatting context的首字母缩写,直译过来是格式化上下文,它是页面中的一块渲染区域,有一套渲染规则,决定了其子元素如何布局,以及和其他元素之间的关系和作用。
常见的FC有BFC、IFC(行级格式化上下文),还有GFC(网格布局格式化上下文)和FFC(自适应格式化上下文).
Box 是 CSS 布局的对象和基本单位, 直观点来说,就是一个页面是由很多个 Box 组成的。元素的类型和 display 属性,决定了这个 Box 的类型。 不同类型的 Box, 会参与不同的 Formatting Context(一个决定如何渲染文档的容器),因此Box内的元素会以不同的方式渲染。

触发条件

  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就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面元素,反之亦然

作用

  1. 不和浮动元素重叠
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<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会覆盖在main的左上角。原因是两个div box都在同一个bfc中,而main不具备bfc,因为:

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

所以main会与所处的bfc左边相接触。可以通过触发main生成bfc来实现自适应两栏布局。

1
2
3
.main {
overflow: hidden;
}

这样触发main的bfc之后,新的box不会和浮动的aside重叠。宽度会根据body和aside的宽度自适应宽度。

  1. 清除内部浮动
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<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高度时,浮动元素也会参与计算

为了达到内部清除浮动,可以触发par生成bfc,这样par的高度会计算内部元素的高度。

1
2
3
.par{
overflow:hidden
}
  1. 防止垂直margin重叠
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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的margin会发生重叠,两个box之间的间隔只有一个100px

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

可以在p外边再包一层容器,生成一个bfc,两个p不处于同一个bfc,就不会重叠margin值了。

创建块格式化上下文(MDN)

下列方式会创建块格式化上下文

  • 根元素(<html>)
  • 浮动元素(元素的 float 不是 none
  • 绝对定位元素(元素的 positionabsolutefixed
  • 行内块元素(元素的 displayinline-block
  • 表格单元格(元素的 displaytable-cell,HTML表格单元格默认为该值)
  • 表格标题(元素的 displaytable-caption,HTML表格标题默认为该值)
  • 匿名表格单元格元素(元素的 displaytable、``table-rowtable-row-group、``table-header-group、``table-footer-group(分别是HTML table、row、tbody、thead、tfoot的默认属性)或 inline-table
  • overflow 值不为 visible 的块元素
  • display 值为 [flow-root](https://drafts.csswg.org/css-display/#valdef-display-flow-root) 的元素
  • contain 值为 layoutcontent或 paint 的元素
  • 弹性元素(displayflexinline-flex元素的直接子元素)
  • 网格元素(displaygridinline-grid 元素的直接子元素)
  • 多列容器(元素的 column-countcolumn-width 不为 auto,包括 ``column-count1
  • column-spanall 的元素始终会创建一个新的BFC,即使该元素没有包裹在一个多列容器中(标准变更Chrome bug)。

reference

什么是BFC?

关于CSS-BFC深入理解

块格式化上下文MDN