div 默认不被tab键聚焦是浏览器正常行为;需键盘导航时应设tabindex="0",配合role和事件监听实现无障碍交互,且模态框关闭后须恢复焦点。

Tab 键跳过 div 是正常的,但你能控制它是否该被跳过
默认情况下,div 和 span 这类非表单元素不会进入 Tab 顺序——这不是 bug,是浏览器对可聚焦元素的默认约定。但如果你需要让某个 div 支持键盘导航(比如自定义下拉菜单、卡片列表),就得主动干预。
最直接的方式是加 tabindex="0":
<div tabindex="0">我能被 Tab 到</div>
注意:tabindex="-1" 只允许用脚本聚焦(element.focus()),不能靠 Tab 键到达;而 tabindex="1" 或更高值会强制插入 Tab 顺序,容易打乱自然流,一般不推荐。
- 只对有交互意图的容器设
tabindex="0",比如可点击的div、带角色的区域 - 避免给纯装饰性或无操作语义的
div加tabindex,否则会干扰屏幕阅读器用户 - 如果用了
tabindex="0",必须配套实现Enter/Space响应逻辑,否则键盘用户点不了
role 属性不等于可聚焦,但它决定焦点后“怎么读”
加了 role="button" 的 div 不会自动获得焦点能力,仍需 tabindex="0"。但它的作用是告诉辅助技术:“这玩意儿行为上是个按钮”,从而触发正确的朗读和交互提示。
常见组合:
<div role="button" tabindex="0" aria-label="关闭弹窗"></div>
-
role="navigation"配合tabindex="-1"+ 脚本聚焦,适合整块导航区的快捷跳转(如按Alt+N直接进导航) -
role="listbox"必须搭配tabindex="0"和aria-activedescendant才能支持方向键导航,不是加个 role 就完事 - 滥用
role(比如给普通段落加role="button")会导致语义混乱,比不加更糟
方向键没反应?大概率缺了 keydown 监听和 preventDefault()
原生 input 或 select 支持方向键是内置行为;但自定义组件(如轮播图、树形控件)必须自己监听 keydown 并手动移动焦点。
关键点:
- 监听事件要绑定在可聚焦的容器上(比如
tabindex="0"的父div),而不是子项 - 对
ArrowUp/ArrowDown等按键调用event.preventDefault(),否则页面可能滚动 - 用
focus()切换子元素焦点时,确保目标元素本身可聚焦(有tabindex="-1"或原生可聚焦)
示例片段:
container.addEventListener('keydown', (e) => {
if (e.key === 'ArrowDown') {
e.preventDefault();
nextItem.focus(); // nextItem 必须已设 tabindex="-1"
}
});
移动端虚拟键盘弹出时,焦点常被“吃掉”或错位
iOS Safari 和部分 Android 浏览器在唤起软键盘后,会重排视口并重置焦点位置——尤其当输入框在滚动区域底部时,焦点可能瞬间丢失或跳到顶部。
- 不要依赖
autofocus,它在软键盘场景下不可靠 - 在
focus后加setTimeout(() => element.scrollIntoView({ block: 'nearest' }), 0)强制对齐 - 避免在
input上同时设readonly和tabindex="0",某些安卓 WebView 会拒绝聚焦 - 测试真机:模拟器里的焦点行为和真实软键盘差异很大
焦点管理最难的部分从来不是“怎么加”,而是“什么时候该移除”——比如模态框关闭后,焦点必须回到触发按钮,否则键盘用户会迷失在页面底部。这个细节,90% 的项目都漏掉。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











