你以为flex布局row-reverse后tab顺序永远对不上?CSS reading-flow今天用一个属性彻底原生化了
flex-direction: row-reverse 写完,Tab 键一按,焦点跳的方向和眼睛看的方向完全相反——这种事,只要做过 RTL 布局或者有逆向排列需求的同学应该都踩过。
以前解法是给每个可聚焦元素塞 tabindex,手动排顺序。问题是你塞了 tabindex,屏幕阅读器的朗读顺序也全乱了,WCAG 2.2 的 Focus Appearance 要求又卡在那里。CSS 一直没人管这件事。
直到 Chrome 137。
reading-flow 是什么
CSS Display Level 4 里的新属性,用来控制 flex/grid 容器里元素的焦点和屏幕阅读器遍历顺序,让它和视觉顺序脱钩。
.container {
display: flex;
flex-direction: row-reverse;
reading-flow: flex-visual;
}
加了 reading-flow: flex-visual 之后,Tab 键在同一个容器里的遍历顺序就会变成 5→4→3→2→1,和视觉顺序完全对齐。不用动 tabindex,也不用动 HTML 结构。
四个值,对应四种场景
flex-visual:焦点顺序跟随视觉排列方式。比如 flex-direction 是 row-reverse,焦点就逆向走;是 column,焦点就按列走。
flex-flow:保持 DOM 的原始顺序,但把这个容器标记成 reading flow 容器,这样容器里的元素才能用 reading-order(见下)。
grid-rows:按行逐行遍历 grid 里的可聚焦元素。一行读完读下一行,跟我们读文章的顺序一致。
grid-columns:按列逐列遍历。先把第一列读完,再读第二列。
/* grid 例子:按行遍历 */
.grid-nav {
display: grid;
grid-template-columns: repeat(4, 1fr);
reading-flow: grid-rows;
}
reading-order:手动接管顺序
如果你连视觉排列都不够用,想要完全自定义顺序,reading-order 可以给单个元素指定整数优先级:
.toolbar {
display: flex;
reading-flow: source-order; /* 把容器变成可自定义顺序的容器 */
}
.toolbar button:nth-child(1) { reading-order: 3; }
.toolbar button:nth-child(2) { reading-order: 1; }
.toolbar button:nth-child(3) { reading-order: 2; }
这样焦点顺序就是 button2 → button3 → button1,完全不依赖 DOM 位置,也不依赖 tabindex 的副作用。
和 tabindex 的本质区别
tabindex 是全局的,屏幕阅读器和键盘焦点都会受影响,还容易产生意外的 z-index 层面的问题。reading-flow 是容器级别的——只影响当前容器内的遍历逻辑,不污染全局。reading-order 则是原子化的,可以精确控制每个子元素。
而且 reading-flow 天然满足 WCAG 2.2 Success Criterion 2.4.11 “Focus Appearance” 的要求——焦点可视化顺序和实际遍历顺序必须一致,这是之前靠 tabindex 很难完美解决的问题。
浏览器支持情况
Chrome 137+ 稳定支持(全球约 70% 覆盖率),Edge 137+ 同步支持。Firefox 和 Safari 暂未实现,属于渐进增强范围:
.toolbar {
display: flex;
flex-direction: row-reverse;
reading-flow: flex-visual;
}
/* 或 */
@supports (reading-flow: flex-visual) {
.toolbar { reading-flow: flex-visual; }
}
什么场景值得用
RTL 布局:阿拉伯文、希伯来文网站,flex-reverse 加 reading-flow 是标配组合。
动态排序的 UI:比如拖拽排序、Filter 下拉面板,视觉顺序变了焦点顺序也得跟着变。
网格导航:产品列表、表格控件,用 grid-rows 替代手写的 tabindex 网格。
复杂工具栏:同时有分组、分隔符、主操作区的工具栏,reading-order 可以完全自定义顺序而不破坏 DOM 结构。
三个字总结:焦点,终于跟着眼睛走了。
下一步
Chrome 137 以上直接用,Firefox/Safari 用户暂时还是得靠 tabindex 兜底。有 RTL 需求的团队可以优先上了——这件事 CSS 自己管了,不用再写一行 JS。
评论区
登录后可评论。