tabindex="0"需配合role和键盘事件,否则仅为“假可聚焦”;tabindex="-1"用于编程聚焦,不参与Tab流;正数tabindex禁用;:focus-visible不可省略。

tabindex="0" 必须配 role 和 keyboard 事件,否则只是“假可聚焦”
加了 tabindex="0 的 div 能被 Tab 键选中,但用户按 Enter 或空格后毫无反应——这不是 bug,是你漏掉了键盘交互逻辑。
-
role属性必须同步设置,比如role="button"或role="checkbox",否则屏幕阅读器读作“普通容器”,用户无法理解用途 - 必须监听
keydown,且只对event.key === 'Enter'和event.key === ' '(注意是空格字符)做响应;空格触发时要调e.preventDefault(),否则页面会意外滚动 - 原生
button元素自带全部行为,优先用它;用div模拟按钮时,tabindex="0"只是起点,不是终点
tabindex="-1" 是编程聚焦的唯一可靠入口,不是“隐藏开关”
模态框打开后调用 element.focus() 却没反应?大概率是目标元素没设 tabindex="-1",或它当前被 display: none / visibility: hidden 隐藏。
-
tabindex="-1"让元素**不进入 Tab 流**,但允许 JS 主动聚焦——这是动态组件(如弹窗、下拉菜单)控制焦点的核心机制 - 模态框首次打开时,应立即对第一个可操作项(如确认按钮)调用
.focus(),该按钮需提前设tabindex="-1" -
focus({preventScroll: true})在 Safari 中静默失效,生产环境建议先检测:if ('preventScroll' in FocusOptions.prototype)
正整数 tabindex(如 1、2、99)在任何场景都不该出现
写 tabindex="1" 不会让它变成“第一个被 Tab 到的元素”,反而会破坏 DOM 自然顺序,让键盘用户和屏幕阅读器同时迷失。
- 多个
tabindex="1"元素中,浏览器只认第一个,其余被忽略;混用tabindex="1"和tabindex="2"后,焦点顺序变成“正数升序 → DOM 顺序 → 0 值元素”,极易错位 - React/Vue 动态渲染时,DOM 插入顺序变化,硬编码的正数
tabindex会直接失效,焦点跳转不可预测 - Flex/Grid 布局下视觉顺序与 DOM 顺序不一致时,正数
tabindex会让键盘导航路径和视觉流彻底割裂
:focus-visible 样式不能省,outline: none 是无障碍红线
清掉默认 outline 后没补 :focus-visible,等于让键盘用户“看不见焦点在哪”,这是最常见也最致命的遗漏。
立即学习“前端免费学习笔记(深入)”;
-
:focus-visible只在键盘触发聚焦时生效,鼠标点击/触摸后自动退去,兼顾体验与可访问性 - 不要用
:focus替代——它对鼠标用户也显示轮廓,体验变差;也不要只靠 JS 检测KeyboardEvent手动切样式,兼容性和维护成本高 - 若需兼容旧浏览器,可用
data-focus-visible-added类配合 polyfill,但现代项目应直接用原生伪类



















