键盘可访问性的核心是确保tab焦点落在逻辑该出现的位置且enter/space能正确触发,依赖html结构、克制使用tabindex和精准js焦点接管。

键盘可访问性的核心不是“让所有东西都能被 Tab 到”,而是确保用户按 Tab 时,焦点落在**逻辑上该出现的位置**,且每个可聚焦项能被 Enter/Space 正确触发——这依赖 HTML 结构、tabindex 的克制使用和 JS 焦点接管的精准时机。
哪些元素默认可聚焦?别乱加 tabindex="0"
原生语义元素(<button></button>、<a href></a>、<input>、<select></select>、<textarea></textarea>)默认就在 Tab 流中。给它们加 tabindex="0" 不仅多余,还可能在 SSR/hydration 场景下引发焦点错位。
- 只对非语义容器(如
<div>、<code><span></span>)加tabindex="0",且必须同步设置role(如role="button"),否则屏幕阅读器读不出交互意图 - 纯装饰性元素(如图标
<svg></svg>容器)加tabindex="0"是反模式,会制造无意义的焦点停顿 -
tabindex="1"或任何正整数必须禁用——它不保证稳定排序,且会破坏 DOM 顺序的语义优先级 - 模态框打开后,立即对第一个可操作项(如“确认”按钮)调用
element.focus();该按钮若为<button></button>,无需设tabindex="-1";若为<div role="button">,则必须加 <code>tabindex="-1" - 用
focus({preventScroll: true})防止页面跳动,但 Safari 不支持该选项,需做兼容检测:if ('preventScroll' in FocusOptions.prototype) - 关闭弹层后,焦点应回退到触发它的元素(如“编辑”按钮),可用
document.activeElement记录或传参保存,不能留空 - 监听
keydown,并第一时间调用event.preventDefault(),防止页面滚动或光标移动 - 优先用
event.key(如"ArrowDown")而非event.code,后者受物理键位影响,不可靠 - Home/End 应跳转到首项/末项,而不是等用户连按多次 Arrow 键;Tab 键离开组件时,需用
focusin+container.contains()检测并循环回内部,而非简单event.preventDefault() - 完全禁用且无需交互时,优先用
hidden属性(语义+行为双重排除) - 必须用 CSS 隐藏时,加
tabindex="-1"或现代inert属性(Chrome/Firefox/Edge 已支持,Safari 18.4+ 支持) -
aria-hidden="true"不影响tabindex行为;若同时存在,必须显式设tabindex="-1",否则可能被意外聚焦 -
<button disabled></button>自动脱离 Tab 流,无需额外干预
动态组件打开时,焦点必须由 JS 主动接管
模态框、下拉菜单、展开面板这类内容是“后加载”的,浏览器不会自动把焦点塞进去。靠 tabindex="0" 等 DOM 顺序是无效的,必须用 JS 调用 .focus(),且目标元素需有 tabindex="-1"。
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
方向键导航必须监听 keydown,且避免默认行为干扰
方向键(ArrowUp、ArrowDown)在 keyup 时可能已被浏览器用于滚动页面,导致你的导航逻辑失效。Home/End 键也需单独处理,不能只依赖 Tab 循环。
隐藏或禁用元素必须真正脱离焦点流
仅用 opacity: 0 或 position: absolute; left: -9999px 隐藏的元素,仍会被 Tab 到。视觉隐藏 ≠ 焦点隔离。
最易被忽略的一点:纯键盘测试必须从新标签页开始,全程禁用鼠标。一旦用鼠标点过任意位置,浏览器就可能缓存焦点状态,后续 Tab 行为不再反映真实首次访问路径——你看到的“正常”,很可能是假象。










