- Published on
格式化上下文 (Formatting Contexts)
CSS 布局的核心在于浏览器如何处理文档流中的盒 (box)。格式化上下文 (Formatting Context) 是 W3C 视觉格式化模型 (Visual Formatting Model) 中的一个关键概念,它定义了一个独立的渲染区域,在这个区域内,一组盒会遵循一套特定的规则进行布局。格式化上下文是所有 CSS 布局(从传统的浮动到现代的 Flexbox 和 Grid)的理论基础。
格式化上下文的核心原则
格式化上下文是页面中的一个独立环境,其内部的布局计算不受外部环境的影响。这一概念建立在三个核心原则之上:
- 隔离性 (Isolation):格式化上下文是一个完全隔离的渲染环境。其内部盒的布局,仅受当前上下文定义的规则约束,完全不受外部上下文的影响,反之亦然。例如,一个块格式化上下文 (Block Formatting Context, BFC) 内部的浮动元素,其高度计算不会影响到外部元素的布局。
- 可扩展性 (Scalability):CSS 的布局模型是高度可扩展的。当需要引入一种全新的布局范式时,CSS 规范只需定义一种新的格式化上下文类型即可,而无需修改现有的盒模型或渲染逻辑。例如,
display: flex
会创建一个伸缩格式化上下文 (Flex Formatting Context),其内部的子元素会遵循 Flexbox 规则进行布局。 - 可预测性 (Predictability):每一种格式化上下文都拥有一套严格且明确的规则集。这意味着,只要确定了一个元素所处的格式化上下文,其布局行为就是完全可以预测的。这种确定性是构建复杂、稳定用户界面的基础。
基础格式化上下文
在现代 CSS 布局(如 Flexbox, Grid)出现之前,所有布局都基于两种基础的格式化上下文。
块格式化上下文 (Block Formatting Context, BFC)
BFC 是页面上一个独立的块级布局环境,其内部的块级盒 (block-level boxes) 会遵循特定的规则进行排列。文档的根元素 (<html>
) 会创建一个初始的 BFC。
BFC 内部的布局规则:
- 内部的盒在垂直方向上,一个接一个地放置。
- 盒垂直方向的距离由
margin
决定。在同一个 BFC 内,相邻块级盒的垂直外边距会发生外边距折叠 (Margin Collapsing)。 - 每个盒的左外边缘,与包含块的左边缘相接触。
- BFC 的区域不会与浮动盒重叠。
- 计算 BFC 的高度时,浮动元素也参与计算。
外边距折叠是指在同一个块格式化上下文 中,相邻的块级盒在垂直方向上的外边距(margin-top
和 margin-bottom
)会合并(折叠)成一个单一的外边距。
- 计算规则: 合并后的大小等于参与折叠的多个外边距中绝对值最大的那个,而非它们的总和。
- 发生场景: 主要发生在三种情况
- 相邻的兄弟元素之间。
- 父元素与其第一个/最后一个子元素之间(当它们之间没有
border
或padding
分隔时)。 - 空的块级盒自身(其
margin-top
和margin-bottom
会折叠)。
- 阻止方法: 最根本的方法是为其中一个元素创建一个新的 BFC(例如,为其设置
display: flow-root
或overflow: hidden
),这会创建一个独立的布局环境,从而阻止其与外部元素发生外边距折叠。
建立新的 BFC: 一个块级容器(如 <div>
)默认情况下并不会为其内容创建新的 BFC,其子元素会参与其父级所处的 BFC。只有当一个块级容器满足至少一个以下条件时,它才会为其内容建立一个全新的 BFC:
- 根元素 (
<html>
)。 - 浮动元素 (
float
的值不为none
)。 - 绝对定位元素 (
position
的值为absolute
或fixed
)。 - 行内块元素 (
display
的值为inline-block
)。 - 表格单元格 (
display
的值为table-cell
)。 - 表格标题 (
display
的值为table-caption
)。 overflow
属性的值不为visible
的块元素。display
的值为flow-root
的元素。
由于 BFC 在计算高度时会包含其内部的浮动元素,因此创建一个新的 BFC 是清除内部浮动的经典方法之一。
.container {
overflow: auto; /* 或 display: flow-root; */
border: 1px solid black;
}
.floated-box {
float: left;
width: 100px;
height: 100px;
}
在这个例子中,.container
因为 overflow: auto
建立了一个新的 BFC,所以它的高度会“包裹”住内部的 .floated-box
。
行内格式化上下文 (Inline Formatting Context, IFC)
当一个块容器盒中不包含任何块级盒时,它就会为其内容建立一个行内格式化上下文。
IFC 内部的布局规则:
- 其内部的行内级盒 (inline-level boxes) 在水平方向上,一个接一个地放置。
- 这些盒会共享一个水平空间,直到该空间被占满,然后换行形成新的行盒 (line box)。
- 行盒的高度由其内部最高的行内盒决定。
- 水平方向的
padding
,border
,margin
会被尊重。垂直方向的padding
和border
视觉上有效,但通常不会影响行盒的高度。垂直方向的margin
完全无效。