J5.11.3ARIA role override设计研究

补充属性会覆盖原生语义,用在原生元素上可能产生冲突而非补充

别名: role 覆盖 · 原生语义冲突 · ARIA 覆盖

概念解释

role 写在原生元素上,不是往上叠一层说明,而是换掉宿主语言已经暴露的角色。<button role="heading"> 在无障碍树里变成标题,不再是按钮;<h2 role="none"> 标题语义被撤掉。补充属性的这个机制叫覆盖(ARIA role override)。作者以为在「补充」,树上发生的是替换。原生键盘行为、默认名称计算、阅读器的元素列表筛选,会按新角色走,或卡在「外观还是按钮、角色已经不是」的夹缝里。

这里要讲的是覆盖如何发生、冲突长什么样,不是「能用原生就用原生」那句选型口号。

机制

无障碍树映射先看显式 role,再看宿主默认。显式值非空,默认角色被丢掉,不会合并成「按钮兼标题」。role="presentation" / none 是故意的删除;其它角色是改派。冲突来自改派之后,宿主还留着自己的行为:<a role="button"> 仍被 Enter 激活,但空格不一定,阅读器却按按钮的合同去等空格;<button role="link"> 的反向也成立。名称计算也可能换槽:按钮吃子文本,某些角色改吃 aria-label 或不再把子文本当名字。

第二层是阅读器的分类索引。用户按 B 找按钮、按 H 找标题、按 F 找表单。覆盖之后,元素从原来的名单消失、出现在另一张名单,或两张都不进。视觉上还是那个控件,浏览模式的快捷键已经对不上。

怎么研究

做最小对照:原生 button;同一 buttonrole="link"h2role="button"buttonrole="presentation"。在检查器读角色,在 NVDA 用元素快捷键(B / H / K)看它出现在哪张列表,再试 Enter 与空格。VoiceOver 转子分类是另一套索引,一并记。

自变量:宿主元素、显式 role、是否 presentation。 因变量:树上的角色、快捷键列表归属、Enter/空格是否仍触发、计算名是否换源。

边界

少数补丁是故意覆盖:把无语义的容器改成 region,或用 role="text" 修破碎的字。表格上的 role="presentation" 用来拆掉布局表,这是删除不是改派,后果是子孙的单元格语义一并消失,波及范围比改一个按钮大。ARIA 1.2 之后部分 role 在某些元素上不合法,引擎可能忽略而不是覆盖,表现为「写了等于没写」。SVG、自定义元素的默认角色本来就弱,覆盖的相对伤害小,但不能反过来说「所以可以随便写」。

怎么落地

  • 不要在已经有正确宿主角色的元素上再写一个不同的 role 去「增强」。
  • 必须改派时,按新角色补齐它的合同(名称、状态、键盘),并接受它会从旧的快捷键名单里消失。
  • presentation / none 拆布局表或装饰列表时,检查子孙是否还需要单元格、列表项语义;需要就不要拆到那一层。
  • 验证:检查器里读角色是否还是宿主默认。再用 NVDA 的 B 和 H 列表找这个控件——出现在错的名单、或两张都找不到,就是覆盖已经改了索引。最后按 Enter 和空格,行为与新角色合同不一致就是冲突而不是补充。

延伸

  • 同组J5.11.1 用于建立元素间关系的属性(标签指向、描述指向)需要引用真实存在的元素 · J5.11.2 实时区域属性的滥用会导致次要信息频繁打断当前播报 · J5.11.4 补充属性无法给元素添加它本身不具备的键盘交互行为
  • 相邻J5.03 语义补充属性 · J5.02 无障碍树与角色
  • 站内检索ARIA role override · role conflict · presentation

同组卡片

快捷操作

分享

分享当前页面

ios_share

https://hci.top/zh/handbook/J5.11.3