用 tabindex 控制焦点流转的核心是明确元素是否应被键盘用户触及,而非排序;应默认依赖 dom 顺序,仅必要时用 tabindex="0" 或 "-1",禁用正整数。

用 tabindex 控制焦点流转,核心不是“排号”,而是明确每个元素是否该被键盘用户触及、何时被触及。科学做法是:默认靠 DOM 顺序,只在必要时用 tabindex="0" 或 tabindex="-1" 做最小干预,彻底避开正整数。
优先信任 DOM 顺序,不主动打乱
浏览器天然按 HTML 源码顺序进行 Tab 导航。只要结构语义清晰(比如导航在 <nav></nav>,主内容在 <main></main>),焦点流就自然符合用户预期。强行给某个视觉上“突出”的按钮设 tabindex="1",反而会让屏幕阅读器用户跳过前面的导航链接,造成认知断层。
- 把页头导航写在 HTML 最前面,它就会第一个被 Tab 到
- 主文章区域紧随其后,不用加任何 tabindex 就能顺延获得焦点
- 侧边栏或页脚放在源码靠后位置,也应保持其自然靠后的 Tab 位置
让非原生元素安全进入 Tab 流:用 tabindex="0" + 语义 + 交互
<div>、<code><span></span> 这类元素默认不可聚焦。加 tabindex="0" 是起点,但三件事必须同步做,否则就是半残废:
- 加上对应语义角色,例如
role="button"或role="checkbox",让辅助技术知道这是什么 - 监听
keydown,对Enter和Space键都做响应(注意空格要event.preventDefault()防止页面滚动) - 配
:focus-visible或:focus样式,让键盘用户清楚看到当前焦点在哪
动态组件中精准接管焦点:用 tabindex="-1" + .focus()
模态框、折叠面板、下拉菜单这类内容出现/消失时,不能靠 tabindex 改顺序,而要用 JS 主动聚焦目标元素:
- 模态框打开后,立即对第一个可操作项(如“确认”按钮)调用
.focus();该按钮需有tabindex="-1"(若它本身不是原生可聚焦元素) - 展开一个 accordion 后,把焦点移到新暴露的首项,而不是留在触发按钮上
- 关闭弹层后,焦点应回退到触发它的元素(比如原“编辑”按钮),可用
document.activeElement记录或传参保存
禁用与隐藏元素:别只靠 CSS,要真正移出焦点流
仅用 opacity: 0 或 position: absolute; left: -9999px 隐藏的元素,仍可能被 Tab 到。必须配合逻辑处理:
- 视觉隐藏且无需交互时,优先用
hidden属性,它同时影响可见性与可访问性 - 必须用 CSS 隐藏时,加
tabindex="-1"或现代inert属性(支持良好)来排除焦点 - 禁用的
<button disabled></button>自动脱离 Tab 流,无需额外设置 tabindex -
aria-hidden="true"不影响 tabindex 行为,若同时存在,需显式设tabindex="-1"











