写过前端的人都踩过这个坑——flex 布局每次用 row-reverse 都要靠 tabindex 补键盘顺序,今天 CSS 把这件事彻底原生化了

写过前端的人都踩过这个坑——flex 布局每次用 row-reverse 都要靠 tabindex 补键盘顺序,今天 CSS 把这件事彻底原生化了。


做过响应式导航栏的同学都知道,有时候视觉上需要把导航项从右往左排列,于是顺手写一句 flex-direction: row-reverse。这下视觉顺序对了——但用户按 Tab 键的时候,焦点跳的顺序还是从左往右,和眼睛看到的完全相反。

更坑的是 CSS Grid。很多复杂的网格布局里,某个元素视觉上在左上角,但 DOM 顺序是第三个孩子,Tab 焦点也就跳到第三个。用户用键盘导航,结果焦点满屏乱飞,像在玩打地鼠。

这个坑以前只有一个解法:tabindex。给每个可聚焦元素手动排个 1、2、3……维护成本高、容易出错、一改布局就要重来。

Chrome 137 终于把这件事原生化了。 新增的 reading-flowreading-order 两个 CSS 属性,让键盘焦点顺序可以声明式地跟随视觉布局,不再需要手写 tabindex


reading-flow:让焦点跟着视觉顺序走

reading-flow 作用在 flex 或 grid 容器上,用来指定子元素的阅读/焦点顺序跟随什么规则。

Flex 容器

.nav {
  display: flex;
  flex-direction: row-reverse; /* 视觉上从右往左排 */
  reading-flow: flex-visual;   /* 焦点也跟着从右往左跳 */
}

flex-visual 让焦点顺序和从左到右的视觉阅读顺序一致。flex-flow 则让焦点跟随 flex 自身的流向(即 flex-direction 指定的顺序)。

Grid 容器

.dashboard {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  reading-flow: grid-rows; /* 按行逐行阅读,焦点顺序也逐行走 */
}

grid-rows 让焦点按行逐行遍历(大多数人的阅读习惯),grid-columns 则按列逐列遍历。


reading-order:细粒度调整单个元素顺序

有时候大部分元素都符合视觉顺序,只需要微调某一个的焦点位置——reading-order 就是干这个的。

.card-grid {
  display: flex;
  reading-flow: source-order; /* 把容器变成阅读流容器 */
}

.card-grid .featured {
  reading-order: -1; /* 这个元素焦点排第一,视觉位置不变 */
}

注意:reading-order 必须配合 reading-flow: source-order 使用,否则无效。


实际场景:修复 row-reverse 导航的 Tab 顺序

这是最容易踩坑的场景。来看看完整写法:

<nav class="breadcrumb">
  <a href="/">首页</a>
  <a href="/products">产品</a>
  <a href="/about">关于我们</a>
</nav>
.breadcrumb {
  display: flex;
  flex-direction: row-reverse;   /* 视觉顺序:关于我们 → 产品 → 首页 */
  gap: 0.5rem;
  padding: 1rem;
  background: #f5f5f5;
  border-radius: 6px;
}

.breadcrumb a {
  /* 以前:只能用 tabindex="3" tabindex="2" tabindex="1" 硬排 */
  /* 现在:两行 CSS 搞定 */
  reading-flow: flex-visual;     /* 焦点顺序自动跟随视觉:关于我们 → 产品 → 首页 */
}

用户用 Tab 键导航时,焦点从「关于我们」开始跳,和视觉顺序完全一致——零 tabindex、零 JavaScript。


浏览器支持与渐进增强

目前只有 Chrome 137+ 支持 reading-flowreading-order,Firefox 和 Safari 还未实现,全球覆盖约 45%。

这意味着必须用渐进增强的思路:

.breadcrumb {
  display: flex;
  flex-direction: row-reverse;
  gap: 0.5rem;
}

/* 支持 reading-flow 的浏览器:焦点顺序跟随视觉 */
/* 不支持的浏览器:回退到 DOM 顺序(和以前一样,但至少能用) */
@supports (reading-flow: flex-visual) {
  .breadcrumb {
    reading-flow: flex-visual;
  }
}

如果 DOM 顺序本身已经和视觉顺序一致(大多数项目是这样的),不支持的浏览器会直接用 DOM 顺序——功能完全正常,只是少了这个增强而已。


什么时候用它、什么时候别用

该用的场景:

  • flex-direction: row-reversecolumn-reverse 的布局
  • Grid 中部分元素用 grid-row / grid-column 定位,导致视觉顺序和 DOM 顺序不一致
  • 轮播图/走马灯组件,DOM 顺序是 1-2-3-4-5,但视觉循环播放
  • 任何「视觉顺序有明确理由和 DOM 顺序不同」的地方

不该用的场景:

  • DOM 顺序本身没问题,加 reading-flow 没有收益
  • reading-flow 当成「可以不规范写 DOM」的借口——视觉顺序和 DOM 顺序不一致的第一反应永远是先改 DOM,reading-flow 是兜底方案,不是偷懒工具

下一步

下次写 flex 布局准备加 row-reverse 之前,先停一下问自己:Tab 焦点顺序对吗?如果不对,加上 reading-flow: flex-visual——一行 CSS 替代以前几十行 tabindex 维护工作。

Chrome 137 自 2025 年 5 月稳定推送,如果你的用户主要用 Chrome(国内桌面场景占比不低),可以直接用上。如果是面向全球用户的组件库,建议搭配 @supports 渐进增强,确保降级体验不退步。

评论区

0 条评论

登录后可评论。

阿柯·前端架构 16 阅读