tabindex仅应使用0和-1:0使非原生元素按DOM顺序入Tab流,需配role、keydown监听和:focus-visible;-1专用于程序聚焦,正整数会破坏焦点逻辑且被WCAG明确反对。

tabindex 只有 0 和 -1 是可信赖的值,正整数(如 1、2)在任何现代无障碍场景中都该被删除——它不解决顺序问题,只制造焦点断裂。
tabindex="0" 是什么,不是什么
它让一个默认不可聚焦的元素(比如 <div>、<span>)按 HTML 源码顺序自然加入 Tab 流。不是“让它第一个被聚焦”,而是“让它别掉队”。
- 原生可聚焦元素(
<button>、<a href>、<input>)已有等效行为,显式加tabindex="0"属于冗余,React/Vue 中还可能触发 hydration 警告 - 必须同步加
role属性(如role="button"),否则屏幕阅读器读作“div”,不是控件 - 不会自动响应
Enter或空格键:得监听keydown,判断event.key === 'Enter'或event.key === ' '(注意是空格字符),并手动调用逻辑 - CSS 若重置了
outline,必须补:focus-visible或至少:focus样式,否则键盘用户完全看不到焦点在哪
tabindex="-1" 不是隐藏,是预留聚焦入口
设为 -1 后,元素彻底退出 Tab 流,但能被 .focus() 主动聚焦——这是模态框、选项卡、下拉菜单等动态组件的焦点控制核心。
- 模态框打开时,首个可操作元素(如关闭按钮)需提前带
tabindex="-1",然后立即执行element.focus() - Accordion 展开后,焦点应移到新暴露内容里的首个可操作项(如内部链接或输入框),而不是留在触发标题上
-
.focus()不自动滚动可视区域,必须紧跟element.scrollIntoView({ block: 'nearest', inline: 'nearest' }) - 移动端 Safari 在未触发用户手势前,对非原生元素调
.focus()可能静默失败;若元素被display: none或visibility: hidden隐藏,.focus()也会失败
为什么 tabindex="1" 是最危险的写法
它不会让你“控制顺序”,只会强制打乱浏览器默认焦点流,且在 SSR、组件复用、辅助技术场景中全面失效。
立即学习“前端免费学习笔记(深入)”;
- 所有正整数都会被排在原生可聚焦元素之前,哪怕 DOM 中它在页脚,Tab 用户一进页面就先碰到它,中间整个编辑区、导航栏全被跳过
- 多个
tabindex="1"元素之间仍按 DOM 顺序聚焦,并非“全部一起第一个”;混用tabindex="1"和tabindex="3"时,tabindex="2"缺失不会补位 - SSR 渲染时服务端与客户端生成的正数值极易不一致,直接触发 hydration 警告
- 屏幕阅读器依赖 DOM 顺序理解上下文,人为插队会让视障用户完全迷失路径——WCAG 明确反对
真正要控制焦点流转,靠的是 DOM 位置 + tabindex="-1" + JS 主动聚焦,而不是给一堆元素硬编号。最容易被忽略的点是:加了 tabindex="0" 却没配 role 和 keydown 处理,或设了 tabindex="-1" 却忘了在组件显示后立刻 .focus() —— 这些地方一漏,键盘用户就卡住不动了。



















