tabindex="0"仅使网格项可聚焦且按dom顺序进入焦点流,不改变视觉位置;tabindex="-1"用于动态内容聚焦接管;正整数tabindex必然导致焦点错乱,wcag明确反对使用。

tabindex="0" 是让网格项可聚焦的起点,不是排序指令
在 CSS Grid 布局中,tabindex="0" 不会改变元素在 DOM 中的位置,也不会让它“跳到第一个”。它只表示:这个原本不可聚焦的 div 或 article 可以被 Tab 键选中,并按 HTML 源码顺序进入焦点流——哪怕它在视觉上被 grid-template-areas 或 order 移到了右下角。
常见错误是给所有网格项统一加 tabindex="0" 后发现焦点顺序和视觉布局不一致。这是因为浏览器只认 DOM 顺序,不认 CSS 重排。如果你的网格项是动态插入(比如 React 中 map 渲染),DOM 顺序可能和预期不同,此时必须检查实际生成的 HTML 结构。
- 只对有交互意图的网格项加
tabindex="0”,比如可点击的卡片、可展开的面板标题 - 必须同步加
role,如role="button"或role="region",否则屏幕阅读器无法识别语义 - 避免给纯展示型网格项(如头像容器、图标
span)加tabindex="0",这会增加无意义的焦点停顿 - 如果网格项包裹了原生可聚焦元素(如内部有
button),外部容器不该再设tabindex="0",否则造成双重焦点
tabindex="-1" 是网格内焦点接管的唯一可靠方式
当用户点击某个网格项触发子面板展开(比如详情浮层、编辑弹窗),焦点不能留在触发项上——必须落到新内容里。这时 tabindex="-1" 不是“隐藏”,而是为 .focus() 提前占位。
典型场景:一个网格项 <div class="card" role="button" tabindex="0">...</div> 点击后显示右侧侧边栏。侧边栏里的第一个 input 必须提前设 tabindex="-1",否则调用 input.focus() 无效或被忽略。
- 不要给整个侧边栏容器设
tabindex="-1",而应设在首个可操作子元素上(如首项input或button) - 确保 DOM 已渲染完成再调用
.focus(),可用requestAnimationFrame或setTimeout(..., 0)延迟执行 - 聚焦后若目标元素被
overflow: hidden或transform遮挡,必须手动补element.scrollIntoView({ block: 'nearest' }) - 关闭侧边栏时,焦点应回退到触发它的网格项,可用
document.activeElement记录或事件参数传递
正整数 tabindex(如 "1", "2")在网格中必然导致焦点错乱
给网格项设 tabindex="1" 并不能让它们按视觉行/列顺序排列。浏览器只会把所有正数项提到整个 Tab 流最前面,再按数值升序排;同值时仍回退到 DOM 顺序。结果往往是:页脚的“导出”按钮比主网格第一行还先被 Tab 到。
更麻烦的是,CSS Grid 的 grid-area 或 JavaScript 动态重排会彻底打乱 DOM 插入顺序,但正整数 tabindex 却还硬编码在模板里——服务端渲染(SSR)和客户端 hydration 后的焦点位置经常不一致,控制台甚至报 focus() failed 警告。
- 绝对不要用
tabindex="1"模拟“从左到右、从上到下”的网格导航 - 方向键(ArrowUp/Down/Left/Right)行为完全不受 tabindex 控制,必须靠 JS 拦截并手动管理焦点迁移
- 若真需网格级键盘导航(如电子表格式输入),应使用
aria-activedescendant+ 容器tabindex="0"+ 子项tabindex="-1"组合 - WCAG 明确反对正整数 tabindex,除非经过无障碍专家评审且有充分理由
Grid 布局中容易被忽略的 tabindex 边界情况
复杂网格常嵌套滚动容器、折叠区域、异步加载区块,这些地方的 tabindex 行为极易出错。最隐蔽的问题不是“加没加”,而是“该不该加”和“加了之后是否被覆盖”。
例如,一个 grid-area: sidebar 区域设置了 overflow-y: auto,里面滚动加载了 10 个卡片。每个卡片都加了 tabindex="0",但用户滚动到底部后按 Tab,焦点却跳回顶部——因为浏览器只遍历当前 DOM 中存在的元素,而滚动加载的新卡片还没进 Tab 流。
- 动态插入的网格项,必须在插入后立即设置
tabindex="0"(或tabindex="-1"),不能依赖初始渲染 - 用
inert属性隐藏的网格区域,也要显式移除或设tabindex="-1",否则仍可能被 Tab 到 -
display: none或visibility: hidden的网格项,即使有tabindex="0"也不会被聚焦;但opacity: 0或position: absolute; left: -9999px的仍会参与 Tab 流 - 父容器设了
tabindex="-1",子元素即使有tabindex="0"也无法被 Tab 到(焦点捕获机制会跳过)
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











