CSS 格式化上下文

CSS 的"格式化上下文"(Formatting Context)可以理解为:浏览器进行布局时使用的一套规则。

它发生在渲染管线的布局阶段:

复制代码
DOM + CSSOM
→ 样式计算
→ 布局(根据格式化上下文排列元素)
→ 绘制
→ 合成

格式化上下文决定:

  • 子元素横着排列还是竖着排列;
  • 是否换行;
  • 宽高如何计算;
  • 外边距是否合并;
  • 浮动元素如何影响其他元素;
  • 元素如何对齐;
  • 剩余空间如何分配。

常见格式化上下文

名称 全称 常见创建方式
BFC Block Formatting Context display: flow-root
IFC Inline Formatting Context 文本、span 等行内内容
FFC Flex Formatting Context display: flex
GFC Grid Formatting Context display: grid
TFC Table Formatting Context display: table

可以简单记忆:

复制代码
BFC:块级元素纵向排列
IFC:文字和行内元素按行排列
FFC:按照主轴、交叉轴排列
GFC:按照行列网格排列
TFC:按照表格规则排列

一、BFC:块级格式化上下文

BFC 全称:

scss 复制代码
Block Formatting Context

在普通块级布局中,元素通常从上往下排列:

ini 复制代码
<div class="container">
  <div class="item">第一项</div>
  <div class="item">第二项</div>
  <div class="item">第三项</div>
</div>
复制代码
┌───────────────┐
│ 第一项         │
├───────────────┤
│ 第二项         │
├───────────────┤
│ 第三项         │
└───────────────┘

不过需要注意:

css 复制代码
display: block;

表示元素以块级方式参与父级布局,但不一定意味着它创建了一个新的、独立的 BFC。

创建独立 BFC 最推荐的方式是:

css 复制代码
.container {
  display: flow-root;
}

BFC 的常见创建方式

css 复制代码
/* 推荐 */
display: flow-root;

/* 浮动 */
float: left;
float: right;

/* 绝对定位 */
position: absolute;
position: fixed;

/* 行内块 */
display: inline-block;

/* overflow 不是 visible 或 clip */
overflow: hidden;
overflow: auto;
overflow: scroll;

其中最推荐:

css 复制代码
display: flow-root;

因为它表达的含义非常明确:

复制代码
为内部内容创建一个独立的块级格式化上下文

使用 overflow: hidden 虽然也能创建 BFC,但可能会意外裁剪内容。

BFC 特性一:包含浮动元素

假设子元素全部浮动:

ini 复制代码
<div class="parent">
  <div class="child"></div>
</div>
css 复制代码
.child {
  float: left;
  width: 100px;
  height: 100px;
}

浮动元素脱离普通文档流,父元素可能无法正确计算高度。

可以给父元素创建 BFC:

css 复制代码
.parent {
  display: flow-root;
}

此时父元素会把浮动子元素计算进自己的高度。

完整示例:

ini 复制代码
<div class="parent">
  <div class="child">浮动内容</div>
</div>
css 复制代码
.parent {
  display: flow-root;
  background: gray;
}

.child {
  float: left;
  width: 100px;
  height: 100px;
  background: skyblue;
}

这也是以前所谓"清除浮动"的一种方式。

BFC 特性二:限制外边距合并

普通块级元素的垂直外边距可能发生合并。

例如:

ini 复制代码
<div class="parent">
  <div class="child">子元素</div>
</div>
css 复制代码
.parent {
  background: gray;
}

.child {
  margin-top: 30px;
}

在某些条件下,子元素的 margin-top 会和父元素发生外边距合并,看起来像父元素整体向下移动。

创建 BFC:

css 复制代码
.parent {
  display: flow-root;
}

可以阻止父元素和子元素之间的这种外边距合并。

但是,同一个 BFC 中相邻块级元素的垂直外边距仍然可能合并:

ini 复制代码
<div class="first"></div>
<div class="second"></div>
css 复制代码
.first {
  margin-bottom: 30px;
}

.second {
  margin-top: 20px;
}

最终间距通常不是:

ini 复制代码
30px + 20px = 50px

而是取较大的值:

scss 复制代码
max(30px, 20px) = 30px

所以不能简单理解为"BFC 内部永远不会发生外边距合并"。

BFC 特性三:减少浮动元素的影响

例如左边有一个浮动元素:

css 复制代码
.left {
  float: left;
  width: 100px;
}

右边内容可能环绕浮动元素。

给右边内容创建 BFC:

css 复制代码
.right {
  display: flow-root;
}

可以使右侧内容形成相对独立的布局区域,避免内容覆盖浮动区域。

不过现代项目通常更推荐直接使用:

css 复制代码
display: flex;

或者:

css 复制代码
display: grid;

二、IFC:行内格式化上下文

IFC 全称:

scss 复制代码
Inline Formatting Context

当一个块级容器中主要包含文本和行内元素时,浏览器会按照行内格式化规则进行布局。

例如:

css 复制代码
<p>
  这是一段文字
  <span>这是 span</span>
  <strong>这是加粗文字</strong>
</p>

这些内容会从左到右排列:

css 复制代码
这是一段文字 这是 span 这是加粗文字

空间不足时自动换行:

css 复制代码
这是一段文字 这是
span 这是加粗文字

常见行内元素:

css 复制代码
<span>
<a>
<strong>
<em>
<img>

IFC 中的重要概念是"行盒":

rust 复制代码
Line Box

浏览器会把一行中的文字和行内元素放入同一个行盒中。

IFC 主要受到这些属性影响:

arduino 复制代码
font-size
line-height
vertical-align
text-align
white-space
word-break

line-height

css 复制代码
p {
  line-height: 30px;
}

它控制每一行行盒的高度。

vertical-align

css 复制代码
img {
  vertical-align: middle;
}

它控制行内元素在当前行盒中的垂直对齐方式。

需要注意:

css 复制代码
vertical-align: middle;

主要用于行内元素、行内块元素或表格单元格,不是普通块级元素的通用垂直居中方案。

三、FFC:Flex 格式化上下文

当设置:

css 复制代码
.container {
  display: flex;
}

容器就创建了 Flex 格式化上下文。

它的直接子元素会成为 Flex 项目:

xml 复制代码
<div class="container">
  <div>项目1</div>
  <div>项目2</div>
  <div>项目3</div>
</div>

默认沿主轴排列:

复制代码
项目1  项目2  项目3

主要概念:

css 复制代码
主轴 main axis
交叉轴 cross axis

常见属性:

css 复制代码
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 10px;

例如水平垂直居中:

css 复制代码
.container {
  display: flex;
  justify-content: center;
  align-items: center;
}

在 Flex 格式化上下文中:

  • 子元素成为 Flex 项目;
  • 浮动对 Flex 项目通常不再按照普通浮动规则生效;
  • vertical-align 对 Flex 项目不起普通行内布局作用;
  • Flex 项目的外边距不会按照普通块级布局方式发生垂直合并;
  • 剩余空间可以通过 flex 分配。

需要注意,只有直接子元素才是 Flex 项目:

xml 复制代码
<div class="container">
  <div class="child">
    <span>孙元素</span>
  </div>
</div>

这里:

css 复制代码
child 是 Flex 项目
span 不是 container 的 Flex 项目

span 如何布局,由 child 自己的格式化上下文决定。

四、GFC:Grid 格式化上下文

设置:

css 复制代码
.container {
  display: grid;
}

容器就建立 Grid 格式化上下文。

Grid 按照行和列进行二维布局:

css 复制代码
.container {
  display: grid;
  grid-template-columns: 200px 1fr 200px;
  gap: 10px;
}

表示三列:

复制代码
200px | 剩余空间 | 200px

例如:

xml 复制代码
<div class="container">
  <div>左侧</div>
  <div>中间</div>
  <div>右侧</div>
</div>

Grid 特别适合:

  • 页面整体结构;
  • 卡片网格;
  • 同时控制行和列;
  • 仪表盘;
  • 复杂表单布局。

Flex 更擅长一维布局:

复制代码
一行或者一列

Grid 更擅长二维布局:

复制代码
同时控制行和列

五、TFC:表格格式化上下文

表格布局使用表格格式化规则:

css 复制代码
<table>
  <tr>
    <td>姓名</td>
    <td>年龄</td>
  </tr>
</table>

也可以通过 CSS 模拟:

css 复制代码
.table {
  display: table;
}

.row {
  display: table-row;
}

.cell {
  display: table-cell;
}

浏览器会根据单元格内容、列宽、跨行跨列等规则计算布局。

现代页面布局一般优先使用 Flex 或 Grid,而不是使用表格布局模拟普通页面结构。

display 的外部和内部布局

现代 CSS 可以把 display 理解成两部分:

复制代码
外部显示类型
内部格式化方式

例如:

css 复制代码
display: flex;

可以理解为:

scss 复制代码
外部:block
内部:flex

也就是:

  • 容器本身像块级元素一样参与父级布局;
  • 容器内部使用 Flex 布局。

而:

arduino 复制代码
display: inline-flex;

表示:

scss 复制代码
外部:inline
内部:flex

也就是:

  • 容器自身像行内元素一样排列;
  • 容器内部仍然使用 Flex 布局。

同理:

css 复制代码
display: grid;

通常可以理解为:

scss 复制代码
外部 block
内部 grid
arduino 复制代码
display: inline-grid;

可以理解为:

scss 复制代码
外部 inline
内部 grid

inline-block 则可以理解为:

scss 复制代码
外部 inline
内部 flow-root

它在外面跟文字一样横向排列,但内部可以拥有独立的块级布局区域。

格式化上下文和其他概念不要混淆

格式化上下文

决定:

复制代码
元素如何排列

例如:

css 复制代码
display: flex;
display: grid;
display: flow-root;

层叠上下文

决定:

复制代码
元素在 Z 轴上的遮挡顺序

例如可能由下面的属性创建:

css 复制代码
position: relative;
z-index: 1;
transform: translateX(0);
opacity: 0.9;

包含块

决定:

复制代码
百分比尺寸和绝对定位以谁为参考

例如:

css 复制代码
.parent {
  position: relative;
}

.child {
  position: absolute;
  left: 50%;
}

这里 child 的定位包含块通常是 parent。

这三个概念分别是:

复制代码
格式化上下文:怎么排
层叠上下文:谁盖住谁
包含块:尺寸和定位参考谁

最后可以这样记忆:

复制代码
普通块布局 → BFC
文字行内布局 → IFC
一行或一列的弹性布局 → FFC
行列二维布局 → GFC
表格布局 → TFC

在现代项目中最常用的是:

css 复制代码
display: flow-root;
display: flex;
display: grid;
相关推荐
雪芽蓝域zzs2 小时前
第6节:远程搜索弹窗(remote 模式),弹窗滚动加载分页
vue.js·elementui
Highcharts.js3 小时前
图表开发实战总结| 7 条“黄金法则”与“性能铁律”
前端·javascript·vue.js·编辑器·时序数据库·highcharts
Wx-bishekaifayuan6 小时前
springboot陨石鉴收系统96265-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·python·spring·课程设计
COOLMO研究AI6 小时前
企业官网服务页的信息架构怎么设计:从用户问题到语义化 HTML
前端·css·html
FYKJ_20107 小时前
springboot家政服务平台66766-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·mysql·spark·课程设计
墨鱼老师7 小时前
Go+Gin+Vue 毕设项目:Gin 框架搭建后端基础接口实战
vue.js·golang·go·gin·前后端分离·计算机毕业设计·go 后端
ym hyd 11115 小时前
试题库管理系统源码 Java+SpringBoot+Vue3 前后分离
java·vue.js·spring boot·毕设
DsirNg20 小时前
断点不该认识设备:组件布局的容器状态治理
css·前端工程化·组件化·响应式布局·css grid·设计系统·container queries
雪芽蓝域zzs21 小时前
第4节:el-select 弹窗事件控制(打开 / 关闭、选中事件、弹窗滚动事件)
vue.js·elementui