写过前端的人都踩过这个坑——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-flow 和 reading-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-flow 和 reading-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-reverse或column-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 渐进增强,确保降级体验不退步。
评论区
登录后可评论。