tabindex 控制元素是否可聚焦、能否进入 Tab 流及相对位置,三者由值的正负零决定:0 按 DOM 顺序加入,-1 仅编程聚焦,正数强制插入但易引发混乱;非原生可聚焦元素需 tabindex="0" 加语义角色与事件监听。

tabindex 不是“给元素编号就能排顺序”的开关,它控制的是元素是否可聚焦、能否进入 Tab 流、以及在流中的相对位置——三者由值的正负零决定,且不可混用。
tabindex 取值的三种行为必须分清
不同数值触发完全不同的焦点逻辑,不是“越大越靠前”:
-
tabindex="0":元素可聚焦,按 DOM 顺序加入 Tab 流(最常用,推荐默认选它) -
tabindex="-1":元素不可通过 Tab 进入,但可通过element.focus()编程聚焦(适合模态框关闭按钮、临时提示等) -
tabindex="N"(N > 0):强制插入 Tab 流指定位置,但会破坏 DOM 顺序一致性,且多个正数易引发维护混乱和屏幕阅读器误读
常见错误是给一堆按钮设 tabindex="1"、tabindex="2"……结果所有都变成“第一个”,因为浏览器只看是否 > 0,不严格按数值排序;更糟的是,当后续插入新元素时,整个顺序得重调。
哪些元素默认可聚焦?哪些必须加 tabindex 才行?
原生可聚焦元素(如 <a href>、<button>、<input>)无需设 tabindex 就能进 Tab 流;而 <div>、<span>、<li> 等默认不可聚焦,加了 tabindex="0" 才行——但仅加还不够:
- 必须配合语义化角色,比如
role="button"或role="checkbox",否则辅助技术无法识别交互意图 - 需手动监听
keydown,对Enter和Space做相同响应(注意Space要event.preventDefault(),否则页面会滚动) - 状态变化要同步
aria-pressed、aria-checked等属性
移动端 Safari 更苛刻:未被用户主动点击过的页面,tabindex 对非原生可聚焦元素基本无效——哪怕写了 tabindex="0",首次 Tab 也跳不过去。
为什么有时 tabindex 设了却没反应?
焦点被拦截或元素实际不可聚焦,比属性写错更常见:
- 父容器有
overflow: hidden或clip-path,导致元素视觉可见但焦点不可达 - 元素
display: none、visibility: hidden或disabled属性存在,tabindex直接失效 - CSS 中写了
outline: none且没提供替代焦点样式,让人误以为“没聚焦”,其实焦点已在 - JavaScript 中某处调用了
event.preventDefault()拦截了keydown.Tab,或用了focus()后又立刻blur()
调试建议:打开浏览器开发者工具,在 Elements 面板选中元素,看右侧面板的 Accessibility 标签页是否显示 “Focusable: true”。如果不是,就别折腾 tabindex,先解决可聚焦性前提。
真正难的不是设 tabindex,而是让每个可聚焦节点在键盘、屏幕阅读器、移动端 Safari、禁用状态、DOM 动态增删下都保持一致行为——多数问题出在语义缺失和事件监听不全,而不是数值填错了。

















