BFC 是一个不太好理解的概念,了解 BFC 可以加深你对网页布局的理解,在了解 BFC 之前先来了解一下 FC 是什么。
FC(Formatting Context)
FC 的全称是格式上下文( Formatting Context),格式化上下文有很多种:
- 块格式上下文(Block Formatting Context, BFC):用于块级盒子,影响块级元素的布局,处理浮动和边距合并等。
- 行内格式上下文(Inline Formatting Context):用于行内盒子,控制文本的排列和行高。
- 表格格式上下文(Table Formatting Context):用于表格元素,影响表格及其内容的布局。
- 弹性格式上下文(Flex Formatting Context):用于弹性盒子(Flexbox),提供灵活的布局能力。
- 网格格式上下文(Grid Formatting Context):用于网格盒子(Grid),允许创建复杂的网格布局。
处于标准流中的盒子属于其中一种格式上下文。
💡块格式上下文(BFC)和行内格式上下文是最基本的两种格式上下文。
其他格式上下文(如表格格式上下文、弹性格式上下文和网格格式上下文)都是在这两种基本格式上下文的基础上,针对特定类型的布局需求而设计的。这些特定的格式上下文在某种程度上可以看作是对块格式上下文和行内格式上下文的扩展和应用。
翻译: 处于标准流中的盒子属于一种格式上下文,在 CSS 2.2 中可以是表格、块级或行内。在未来的 CSS 版本中,将引入其他类型的格式上下文。块级盒子参与块格式上下文,行内盒子参与行内格式上下文。表格格式上下文在关于表格的章节中进行了描述。
-
块级元素的布局属于 Block Formatting Context(BFC),也就是 block level box(块级盒子)都在 BFC 中布局。
-
行内级元素的布局属于 Inline Formatting Context(IFC),而 inline level box(行内及盒子) 都在 IFC 中布局。
BFC(Block Formatting Context)
翻译:9.4.1 块级格式化上下文
浮动、绝对定位的元素、不是块级盒子的块容器(如内联块、表单元格和表标题),“overflow”不是“visible”(除非该值已传播到视口)的块级盒子为其内容建立新的块格式化上下文。
MDN 上有整理出在哪些具体的情况下会创建 BFC:
● 根元素(<html>
)
● 浮动元素(元素的 float
不是 none
)
● 绝对定位元素(元素的 position
为 absolute
或 fixed
)
● 行内块元素(元素的 display
为 inline-block
)
● 表格单元格(元素的 display
为 table-cell
,HTML表格单元格默认为该值),表格标题(元素的 display
为 table-caption
,HTML表格标题默认为该值)
● 匿名表格单元格元素(元素的 display
为 table
、table-row
、 table-row-group
、table-header-group
、table-footer-group
(分别是HTML table、 row、tbody、thead、tfoot 的默认属性)或 inline-table
)
● overflow
计算值(Computed
)不为 visible
的块元素
● 弹性元素(display
为 flex
或 inline-flex
元素的直接子元素)
● 网格元素(display
为 grid
或 inline-grid
元素的直接子元素)
● display
值为 flow-root
的元素
BFC 的定义
翻译:在块格式上下文中,盒子一个接一个地垂直排列,从包含块的顶部开始。两个兄弟盒子之间的垂直距离由其 margin 属性决定。在块格式上下文中,相邻块级盒子之间的垂直边距会合并。
在块格式上下文中,每个盒子的左外边缘触碰到包含块的左边缘(对于右到左的格式,右边缘则触碰)。即使存在浮动情况也是如此(尽管盒子的行盒可能因浮动而缩小),除非该盒子建立了新的块格式上下文(在这种情况下,盒子本身可能因浮动而变得更窄)。
简述如下:
● 在BFC中,box 会在垂直方向上一个挨着一个排布。
● 垂直方向的间距由 margin 属性决定。
● 在同一个 BFC 中,相邻两个 box 之间的 margin 会合并(collapse)。
● 在 BFC 中,每个元素的左边缘紧挨着包含块的左边缘。
所以之前遇到的 margin 合并,浮动高度塌陷问题可以说是一种特性。
解决 margin 合并问题
在同一个 BFC 中,相邻两个 box 之间的 margin 会合并(collapse) 。
💡官方定义:在块格式上下文中,盒子一个接一个地垂直排列,从包含块的顶部开始。两个兄弟盒子之间的垂直距离由其 margin 属性决定。在块格式上下文中,相邻块级盒子之间的垂直边距会合并。
解决方法:
● 只设置一个 margin。
● 让两个 box 属于不同的 BFC,使其不再相邻。
<div class="container">
<div class="box1"></div>
</div>
<div class="box2"></div>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
/* .box {
overflow: auto;
} */
.container {
overflow: auto;
}
.box1 {
height: 200px;
width: 400px;
background-color: orange;
margin-bottom: 30px;
}
.box2 {
height: 150px;
background-color: purple;
margin-top: 50px;
}
</style>
</head>
<body>
<div class="container">
<div class="box1"></div>
</div>
<div class="box2"></div>
<p>
<a href=""></a>
<span></span>
</p>
</body>
</html>
解决浮动高度塌陷
网上有很多说法,说 BFC 可以解决浮动高度塌陷,可以实现清除浮动的效果,但是从来没有给出过 BFC 可以解决高度塌陷的原理或者权威的文档说明。
他们也压根没有办法解释,为什么可以 BFC 解决浮动高度的塌陷问题,但是不能解决绝对定位元素的高度塌陷问题(绝对定位元素脱标,然后高度塌陷)。
标准文档:https://www.w3.org/TR/CSS22/visudet.html#root-height
翻译 10.6.7 块格式上下文根元素的“自动”高度
在某些情况下(参见上面的第 10.6.4 和 10.6.6 节),建立块格式上下文的元素的高度计算如下:
如果它只有行内级子元素,则高度是最上方行盒的顶部与最下方行盒的底部之间的距离。
如果它有块级子元素,则高度是最上方块级子元素盒子的顶部边距与最下方块级子元素盒子的底部边距之间的距离。
绝对定位的子元素被忽略,相对定位的盒子在计算时不考虑其偏移。请注意,子盒子可以是匿名块盒子。
此外,如果该元素有任何浮动后代,其底部边距边缘位于元素的底部内容边缘之下,则高度会增加以包含这些边缘。 只有参与此块格式上下文的浮动元素被考虑,例如,绝对定位的后代中的浮动或其他浮动则不被计入。
BFC 解决高度塌陷需要满足两个条件:
- 浮动元素的父元素触发 BFC,形成独立的块级格式化上下文(Block Formatting Context)
- 浮动元素的父元素的高度为 auto
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.container {
background-color: orange;
position: relative;
overflow: auto;
}
.item {
width: 400px;
height: 200px;
box-sizing: border-box;
border: 1px solid #000;
float: left;
background-color: #f00;
/* position: absolute; */
}
</style>
</head>
<body>
<div class="container clear_fix">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</body>
</html>
BFC 自动(auto)高度简述:
- 如果只有 inline-level,是行高的顶部和底部的距离。
- 如果有 block-level,是由最顶层的块上边缘和最底层块盒子的下边缘之间的距离。
- 如果有绝对定位元素,将被忽略。
- 如果有浮动元素,那么会增加高度以包括这些浮动元素的下边缘。