aria-selected只能用于特定角色元素,表格中需为显式设role="row"并置于role="grid"容器内;选项卡中仅role="tab"元素可设该属性,且须与tabpanel通过aria-controls关联,并同步更新aria-hidden;javascript必须手动同步aria属性与视觉状态,确保三者一致。

aria-selected 不能直接用于 <tr> 或 <code><td>
<p>WAI-ARIA 规范明确限制 <code>aria-selected 的可用角色(role):它只对 gridcell、option、row、tab、treeitem 等特定 role 生效。普通 <tr> 默认 role 是 <code>row,但若未显式声明 role="row",屏幕阅读器可能忽略 aria-selected 属性——这正是多数人“设了没反应”的根本原因。
实操建议:
- 表格中需选中的行,必须显式添加
role="row",且该<tr> 必须位于具有 <code>role="grid"的容器内(如<table role="grid"> 或 <code><div role="grid">) <li> <code>aria-selected="true"才会被正确识别;仅设为"false"或省略不写,等同于未选中,无需冗余设置 - 避免在
<tbody> 或 <code><thead> 上误加 <code>aria-selected—— 它们不是可选中单元,属性会被忽略选项卡(tabs)中
aria-selected的正确绑定方式选项卡组件依赖
tablist→tab→tabpanel的结构链,aria-selected只能放在role="tab"元素上,且必须与对应tabpanel的id通过aria-controls关联。常见错误现象:
- 点击 tab 后视觉高亮,但屏幕阅读器仍读“未选中”——大概率是漏写了
role="tab",或aria-selected写在了父容器(如<li>)而非实际触发元素(如<button></button>)上 - 多个 tab 同时为
aria-selected="true"—— ARIA 要求同一tablist中有且仅有一个选中态,否则会破坏键盘导航逻辑(如 → / ← 切换失效) - 未同步控制
tabpanel的aria-hidden:选中 tab 对应的 panel 应设aria-hidden="false",其余设aria-hidden="true",否则焦点管理会出错
用 JavaScript 同步更新
aria-selected和视觉状态不能只靠 CSS 类切换,必须同步操作 ARIA 属性。浏览器不会自动将
.active类映射为aria-selected。实操要点:
- 监听 click 或 keyboard 事件(如 Space、Enter)后,先清除所有同类元素的
aria-selected,再给目标元素设aria-selected="true" - 对表格行,推荐用
document.querySelector('[role="row"][aria-selected="true"]')获取当前选中行,而不是依赖 class 名——更健壮,也符合 ARIA 意图 - 注意 DOM 更新时机:若使用框架(如 React),确保 ARIA 属性在渲染完成后的 DOM 节点上真实存在,避免 SSR/ hydration 不一致导致属性丢失
兼容性与测试盲区
aria-selected在主流屏幕阅读器(NVDA、VoiceOver、JAWS)中支持良好,但有两个容易被忽略的细节:- 某些旧版 JAWS(≤2018)对
role="grid"中的aria-selected响应延迟,需配合aria-activedescendant手动管理焦点位置,否则键盘导航可能跳过选中行 - 移动端 VoiceOver 在表格中 swipe 导航时,不会主动 announce
aria-selected,必须额外用aria-live="polite"区域播报“已选中第 X 行”,否则视障用户无法感知状态变更 - 自动化测试工具(如 axe-core)能检测
aria-selected是否缺失,但无法验证其值是否与视觉/逻辑状态一致——必须人工用键盘 + 屏幕阅读器走查
真正麻烦的不是加属性,而是让每个交互路径(鼠标、键盘、触摸、辅助技术)都保持 ARIA 状态、DOM 状态、UI 状态三者严格同步。少一个环节,就等于把部分用户挡在门外。
- 点击 tab 后视觉高亮,但屏幕阅读器仍读“未选中”——大概率是漏写了











