Back to Blog
· 3 min read

CSS Grid

CSS

CSS Grid

最初学习 Grid 布局时,按照网上的教程,大概是这么个流程,先摸 grid-template-columns,再记 grid-column: 1 / 3,然后学 grid-area,接着就开始用它做布局。很多人就此打住,把 Grid 当”更强的 Flexbox”用。

这个理解不能说错,但真的只是皮毛。

真正的重点是:CSS Grid 不是布局工具,而是二维空间系统。

Grid 的核心不是 cell,而是 line

线网模型

当你写这行 CSS:

grid-template-columns: 200px 1fr 200px;

浏览器内部生成的并不是三个”格子”,而是一组网格线:

line 1 | track 1 | line 2 | track 2 | line 3 | track 3 | line 4

线的数量 = 轨道数量 + 1。

grid-column: 1 / 3,表示把这个元素放在 line 1 和 line 3 之间的空间里。这不是排版,是坐标定位。

定位模型的区别

模型本质特点
position: absolute像素坐标手写坐标,不易维护
display: flex流式排序单轴排列,天然适应内容
display: grid线性坐标系统结构化坐标,可组合

Grid 本质上是个二维绝对定位系统,但跟 absolute 不一样的是,它的坐标是结构化的、可组合的、可语义化的。

Grid Line 语义化

数字写法的问题

grid-column: 2 / 5;
  • 不可读——看到 2 / 5 你完全不知道这是什么东西
  • 不可维护——调整布局时一个数字改动可能引发连锁反应
  • 跟设计语义完全不沾边

更麻烦的是,在最左边加一列,所有基于数字的定位都得重新算一遍。

Named Lines

CSS Grid 允许给网格线命名:

grid-template-columns:
  [sidebar-start] 240px
  [sidebar-end content-start] 1fr
  [content-end];

然后这样用:

.sidebar {
  grid-column: sidebar-start / sidebar-end;
}

.main {
  grid-column: content-start / content-end;
}

除了实现语义替换,在考虑布局时的角度也有变化,从数字坐标系统,变成空间语义系统。布局不再是”元素 A 在第 2 到第 5 条线之间”,而是”侧边栏占侧边栏的区域,主内容区占主内容区的区域”,让组件的语义与位置的语义直接匹配。

主流布局模式

这是 Web 应用常见的 Grid 结构,内容居中:

grid-template-columns:
  [full-start] minmax(24px, 1fr)
  [content-start] min(1200px, 100%)
  [content-end] minmax(24px, 1fr)
  [full-end];

表面看,这是在”让内容居中”。但它实际在定义三层空间结构

| gutter (auto) | content (bounded) | gutter (auto) |

三个空间区域,每个都有明确的语义和约束:

  • 左右 gutterminmax(24px, 1fr) 保证最小 24px 安全边距,同时能随屏幕自动扩展
  • 内容区域min(1200px, 100%) 确保最大宽度 1200px,小屏自动占满

这里有一个思路的变化,从“考虑怎么居中内容”到“怎么将不同类型的东西放在它的位置上”。

容器先行

以前的思维惯性是,先写 item

.sidebar { width: 240px; }
.main { margin-left: 240px; }

这种方式的问题是每个组件都得知道布局的存在——它们必须知道自己该往哪挪、该留多少空间,强耦合,很多布局问题就是这么来的。

在 Grid 最佳实践中,应该是先规划容器

.layout {
  display: grid;
  grid-template-columns: 240px 1fr;
}

组件只需要声明自己属于哪一列,不用知道任何布局细节:

.sidebar { grid-column: 1; }
.main { grid-column: 2; }

本质转变是:从”组件决定布局”到”布局决定组件”。父容器定义空间规则,子元素只需要选自己属于哪个空间。

Subgrid

Flexbox 有一个限制,每个 Flex 容器都是独立的布局系统,在每个 Flex 组件内,都需要提供额外的定位措施。

这导致嵌套的 Flex 布局天然不对齐——子元素在子容器内居左,兄弟容器的子元素可能在完全不同的位置。这种不对齐需要大量 hack 来解决:额外的 wrapper、负 margin、calc 计算……

Subgrid 允许子布局继承父 Grid 的轨道结构

.card {
  display: grid;
  grid-template-columns: subgrid;
}

整个应用可以共享:

  • 统一的列系统
  • 统一的对齐规则
  • 统一的间距系统

以 Notion、Linear 为例

它们的布局结构,核心并不是”一堆组件”,而是一个全局统一的空间系统。每个卡片、每个弹窗、每个侧边栏都在同一个坐标体系下运转。选择合适的布局架构,能达到事半功倍的效果,如果使用 absolute 或 flex 来实现类似布局,则要花费更多功夫。

CSS Grid Lanes:瀑布流布局的首选

Safari Technology Preview 234 引入了 CSS Grid Lanes。

display: grid-lanes 创建瀑布流布局:

.container {
  display: grid-lanes;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 16px;
}

定义列时创建”瀑布”布局,定义行时创建”砖块”布局。

flow-tolerance 属性

Grid Lanes 引入了一个新属性 flow-tolerance,控制元素在轨道间移动的积极性:

.container {
  flow-tolerance: 2em;
}

默认值 1em。这个属性解决的是:元素该跳到更短的轨道上,还是保持当前位置?这个权衡直接影响最终布局的紧凑程度。

适合的场景

Grid Lanes 特别适合:

  • 照片画廊
  • 报纸风格的文章网格
  • 电商产品列表
  • mega menu

过去这些布局都需要 JavaScript 库,现在纯 CSS 能做到了。

布局思路

层级本质思维模式
Component内容UI = 组件树
Flex排列UI = 流式组合
Grid空间UI = 空间坐标
System规则UI = 物理法则

用 Flex 思考时,你在想”元素该怎么排列”。

用 Grid 思考时,你在想”空间该怎么分配”。

用 Subgrid + Grid Lanes 思考时,你在想”整个界面的空间规则是什么”。

CSS Grid 刚普及时,大部分教程把它介绍成”二维版 Flexbox”。这个类比有帮助,但也容易让人停在表面。

当你真正摸透 Grid 的线网模型,你会发现它解决的不是”怎么排列元素”,而是”怎么定义空间规则”。很多以前需要 hack 才能解决的布局问题,一旦接受这个转变,就变得自然而然了。

Subgrid 和 Grid Lanes 把这个思维继续扩展:从单层空间系统,到多层嵌套的统一空间系统,再到支持瀑布流的动态空间系统。CSS 正在成为一个真正强大的布局语言,Grid 是这整个演进的核心。

参考文档

WebKit Blog: Introducing CSS Grid Lanes