tabindex不能重排键盘导航顺序,真正决定焦点流向的是dom结构;grid仅改变视觉位置,不改变tab流;应慎用正整数tabindex,优先用tabindex="0"配合role和keydown处理,动态聚焦用tabindex="-1"配合.focus()。

复杂网格布局里,tabindex 不是用来“设计”键盘导航流向的——它只能修复断裂,不能重排顺序。真正决定焦点怎么走的,是 DOM 结构本身,不是你写的数字。
为什么 grid 布局中 tabindex="1" 必然导致焦点错乱
CSS Grid 改变的是视觉位置,不是 DOM 顺序。浏览器只按 HTML 源码顺序处理 Tab 流,tabindex="1" 这类正整数会把所有匹配元素强行提到整个 Tab 序列最前面,再按数值升序排;但多个同值(比如全设为 1)时,仍回退到 DOM 插入顺序。
常见后果包括:
- 页脚的“导出”按钮比主网格第一行还先被 Tab 到
- React 动态渲染后,同一组
tabindex="1"按钮今天从上到下、明天从左到右进流 - 屏幕阅读器把第一个
tabindex="1"当作逻辑起点,用户一进页面就听到“导出”,完全丢失编辑区上下文
tabindex="0" 该加在哪些 grid 子项上
只加在有交互意图、又不是原生可聚焦元素的容器上,比如 <div role="button"> 或 <code><h3 role="tab"></h3>。它只是让这个元素“能被 Tab 键碰到”,不等于“按了就有反应”。
必须同步满足:
- 配
role属性(如role="button"),否则屏幕阅读器读作“div”而非“按钮” - 监听
keydown,对Enter和Space都触发操作;Space要调e.preventDefault(),否则页面滚动 - 提供
:focus-visible样式,否则键盘用户看不到焦点在哪 - 避免给纯展示型网格项(如头像容器、图标
<span></span>)加tabindex="0",这会增加无意义停靠点
tabindex="-1" 是动态聚焦的唯一可靠入口
当网格项点击后展开侧边栏、弹出面板或切换 tab 内容时,焦点不能留在触发项上,必须落到新内容里。这时 tabindex="-1" 不是“隐藏”,而是为 .focus() 提前占位。
关键实操要点:
- 目标元素(如侧边栏首个
<input>)必须在 HTML 中就带tabindex="-1",否则.focus()无效或被忽略 - 别给整个容器设
tabindex="-1",而应设在首个可操作子元素上 - 确保 DOM 已渲染完成再调用
.focus(),可用requestAnimationFrame或setTimeout(, 0)延迟 - 聚焦后若目标被
overflow: hidden或transform遮挡,必须手动补element.scrollIntoView({ block: 'nearest' })
真正影响网格键盘导航体验的,从来不是 tabindex 的数值,而是 DOM 是否贴近语义流、JS 是否在状态切换时精准接管焦点、以及 CSS 是否避免用 opacity: 0 或 position: absolute 隐藏却未阻断聚焦。这些地方一漏,tabindex 再怎么设都白搭。











