tabindex="0"加了但键盘无反应,根本原因是未同步设置role属性、未监听enter/space键事件且未调用e.preventdefault()。

tabindex="0"加了但键盘按了没反应,问题出在哪
加了 tabindex="0 只解决“能被 Tab 键停靠”,不解决“按了能干啥”。常见现象是:Tab 到一个 div role="button" 上,按 Enter 或空格毫无反馈——这不是浏览器 bug,是你漏掉了三件事:
- 没写
role属性,比如role="button";屏幕阅读器读它就是“普通容器”,用户不知道这是按钮 - 没监听
keydown事件,且只对event.key === 'Enter'和event.key === ' '(注意是空格字符)做响应 - 空格触发时没调
e.preventDefault(),导致页面意外滚动
原生 button 元素自带全部逻辑,优先用它。非要用 div 模拟,tabindex="0" 只是起点,不是终点。
模态框打开后 focus() 失效,90% 是 tabindex="-1" 没配对
tabindex="-1" 不是“隐藏开关”,而是“编程聚焦入口”:它让元素不进 Tab 流,但允许 JS 主动聚焦。模态框打开后 element.focus() 静默失败,大概率因为目标元素没设 tabindex="-1",或者它当前被 display: none 或 visibility: hidden 隐藏。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 模态框内第一个可操作项(如确认按钮)必须在 HTML 中就带
tabindex="-1" - 打开后立刻调用
.focus(),不要等异步渲染完成再聚焦 - Safari 不支持
focus({preventScroll: true}),生产环境建议先检测:if ('preventScroll' in FocusOptions.prototype) - 聚焦后若元素被
overflow: hidden或绝对定位遮挡,需补element.scrollIntoView({ block: 'nearest' })
grid 布局里乱加 tabindex="-1",反而让内部按钮无法聚焦
给整个 display: grid 容器加 tabindex="-1",会导致所有子元素(哪怕有 tabindex="0" 或是原生 button)都被跳过——浏览器会跳过该节点及其子树的默认 Tab 流。
- 正确做法:仅对纯语义性容器(如
role="grid"的外层)设tabindex="-1",表示“我只负责语义,不收焦点” - 每行用
role="row",每个单元格用role="gridcell",内部可交互元素(如input、button)保留原生聚焦能力 - 避免把
button包在tabindex="-1"的div里,否则焦点路径被阻断 - 网格中单选按钮组必须用
table+aria-labelledby实现,CSS Grid 无法提供行列语义
为什么永远别写 tabindex="1"
tabindex="1" 不会让元素变成“第一个被 Tab 到的”,只会把它塞进所有正数里排最小——但多个 tabindex="1" 仍按 DOM 顺序走,和没设一样。更糟的是,混入 tabindex="0" 后,Tab 流变成“正数 → 0 值 → 其他”,完全失控。
- React/Vue 动态渲染时,硬编码正数 tabindex 会因 SSR hydration 差异或组件重挂载而失效
- 移动端 Safari 对
tabindex="1"支持极差,甚至可能触发警告 - 屏幕阅读器把第一个
tabindex="1"当作逻辑起点,如果它是页脚按钮,用户一进页面就听到“导出”,主区域上下文全丢 - WCAG 明确不推荐,实测中 90% 的键盘用户会因此迷失
真正需要控制焦点顺序,靠的是 DOM 位置本身——导航栏放顶部,它自然第一个被 Tab 到;靠正数 tabindex 强行干预,等于主动放弃可维护性和可预测性。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










