WWDC Quick Look 💓 By SwiftGGTeam
Learn CSS Grid Lanes

Learn CSS Grid Lanes

观看原视频

Highlight

Safari 26.4 引入 display: grid-lanes,用三行 CSS 替代 JavaScript 瀑布流库,并通过 flow-tolerance 属性解决 DOM 顺序与视觉顺序不一致导致的键盘焦点跳跃问题。

核心内容

瀑布流布局的困境

做过图片墙、卡片流的开发者都经历过这个场景:图片高度参差不齐,用 Flexbox 会留下大片空白,用 CSS Grid 又必须把每张图塞进等高的单元格。三种妥协方案都不理想:拉伸会变形,缩放会溢出,裁剪会丢失内容。最后大家只能引入 JavaScript 库,在客户端计算每张图的高度再动态定位。这套方案能跑,但额外增加了脚本体积和运行时开销,在移动端滚动时尤其吃力。

00:57

Grid Lanes 的定位

CSS 现有两种布局模式回答了同一个问题:元素放在哪里、占多少空间。Flexbox 只控制一个轴,内容沿单条轨道流动,换行时继续沿同一方向排列。Grid 控制两个轴,把元素放进行列交叉的单元格里。Grid Lanes 卡在两者之间:只锁死一个轴,另一个轴完全交给内容自己撑开。

01:13

结果是元素被分发到多条轨道里,每条轨道独立计算高度。浏览器把每个新元素放进当前最短的列,后续元素依次填补下方空隙。这种”最短优先”算法天然实现了紧密排列,同时保留每个元素的自然比例。

03:07

从瀑布流到砖墙,只改一个属性

Grid Lanes 支持两种视觉形态。默认是瀑布流:定义列轨道,内容自上而下填充各列。把 grid-template-columns 换成 grid-template-rows,布局立刻变成横向砖墙,元素从左到右逐行流动。两种模式共用同一套语法,切换成本极低。

04:31

flow-tolerance 解决无障碍痛点

Grid Lanes 被放进 Accessibility & Inclusion 轨道,核心原因是 flow-tolerance 属性。传统”最短优先”算法有个副作用:当相邻两列高度接近时,下一个元素可能跳到右侧较短的列,导致视觉顺序和 DOM 顺序错位。键盘用户按 Tab 键时,焦点在屏幕上左右横跳,屏幕阅读器读出的内容顺序也是乱的。

flow-tolerance 的默认值是 1em。它的规则是:如果较高列与最短列的高度差在容差范围内,浏览器优先把元素放入 DOM 顺序更靠前的列,而不是死磕绝对最短列。这个微小的视觉妥协,换来了线性的阅读顺序和稳定的焦点路径。

07:15

详细内容

创建 Grid Lanes 容器

03:58

最简声明只需要一个属性:

.container {
  display: grid-lanes;
}

加上列定义和间距:

.container {
  display: grid-lanes;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}

关键点:

  • display: grid-lanes 启用新布局模式,语法与 display: grid 平行
  • repeat(3, 1fr) 把容器宽度分成三等份,fr 是 fractional unit 的缩写
  • gap: 10px 的写法与 CSS Grid 完全一致
  • 只能定义 grid-template-columnsgrid-template-rows 中的一个,不能同时写两者

砖墙变体

04:33

把列定义换成行定义,瀑布流变成砖墙:

.container {
  display: grid-lanes;
  grid-template-rows: repeat(3, 1fr);
  gap: 10px;
}

关键点:

  • grid-template-rows 替代 grid-template-columns
  • 元素沿行方向流动,形成横向排列
  • 方向二选一,不能混用

响应式列宽

05:10

让浏览器自动决定塞下几列:

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

更复杂的重复模式:

.container {
  display: grid-lanes;
  grid-template-columns:
    repeat(auto-fill,
      minmax(8rem, 1fr)
      minmax(14rem, 2fr));
  gap: 10px;
}

关键点:

  • auto-fill 根据容器宽度自动创建尽可能多的列
  • minmax(200px, 1fr) 保证每列至少 200px,剩余空间均分
  • 可以定义宽窄交替的重复模式

控制单个元素

05:45

让某个元素跨两列:

.container {
  display: grid-lanes;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 10px;
}

.item {
  grid-column: span 2;
}

精确指定起始位置:

.item {
  grid-column: 2 / span 2;
}

关键点:

  • grid-column: span 2 沿列方向跨越两格
  • grid-column: 2 / span 2 从第 2 列开始,跨 2 列
  • 可以控制列位置,但行位置由 Grid Lanes 自动计算

与 Subgrid 集成

06:22

一个跨两列的卡片,内部元素与父级网格对齐:

.container {
  display: grid-lanes;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 10px;
}

.item {
  display: grid-lanes;
  grid-template-columns: subgrid;
  grid-column: span 2;
}

也可以嵌套普通 Grid:

.item {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: span 2;
}

关键点:

  • subgrid 让子元素继承父级的列轨道定义
  • 图片占一列,文字占另一列,各自按内容自适应
  • Grid Lanes 和普通 Grid 可以互相嵌套

flow-tolerance 调优

08:37

默认行为:

.container {
  display: grid-lanes;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  flow-tolerance: normal;
}

自定义容差:

.container {
  display: grid-lanes;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  flow-tolerance: 2.1em;
}

关键点:

  • 默认值为 1em
  • 浏览器比较各列高度,如果高度差在容差内,优先按 DOM 顺序填充
  • 容差越大,视觉顺序越接近 DOM 顺序,但列高差异可能更明显
  • Safari 开发者工具提供 Grid Lanes 专用 Overlay,显示列线、元素顺序编号和间隙

核心启发

  • 做什么:把 App 内的图片瀑布流从 JavaScript 库迁移到原生 CSS 为什么值得做:减少脚本体积,消除运行时高度计算,WKWebView 内滚动更流畅 怎么开始:用 @supports (display: grid-lanes) 做渐进增强,支持的浏览器走原生,不支持的继续用旧方案

  • 做什么:给内容型网站加砖墙式时间轴布局 为什么值得做:Grid Lanes 的横向流动模式天然适合展示时间线或步骤流程 怎么开始:把 grid-template-columns 换成 grid-template-rows,配合 span 控制重点卡片

  • 做什么:用 flow-tolerance 修复现有瀑布流的无障碍问题 为什么值得做:很多第三方瀑布流库都存在 DOM 顺序与视觉顺序不一致的缺陷 怎么开始:把 flow-tolerance: 1em 加到 Grid Lanes 容器上,再用 Safari 开发者工具的 Overlay 检查 Tab 焦点路径

  • 做什么:在跨列卡片里用 subgrid 对齐图文 为什么值得做:大图配文的卡片经常需要内部网格与外部网格对齐 怎么开始:卡片加 grid-column: span 2grid-template-columns: subgrid,图片和文字各自占一列

关联 Session

评论

GitHub Issues · utterances