可访问名称按固定优先级从多个来源计算得出,顺序可被开发者覆盖
别名: 可访问名称 · AccName · aria-labelledby · aria-label
概念解释
辅助技术嘴里那个控件的名字,不是「屏幕上写了什么」的别称。它是按 AccName 算法从多个来源计算出来的:可访问名称计算(accessible name computation)。优先级大致是 aria-labelledby 指向的节点文本,然后 aria-label,再然后宿主语言自己的槽(<label>、按钮的子文本、alt、输入框的 value 等),再往后才轮到 title。排在前面的来源一旦给出非空结果,后面的整段不再参与。开发者加一条更高优先级的属性,就能覆盖用户正在看的那几个字。
机制
计算是一次有序折叠,不是拼接。aria-labelledby 按 ID 顺序把若干节点的文本抽出来合成一个名字,并且允许指向看不见的节点。aria-label 是作者直接写入的字符串,它会压过按钮里面那几个字,而不是跟它们相加。原生槽位各管各的:复选框靠关联的 label,图靠 alt,链接靠子孙文本。title 是垫底,许多阅读器还把它当成描述而不是名称。
第二层是「可覆盖」这件事的工程含义。优先级表把作者属性和可见文本放进同一条赛道,作者属性在前。于是「改名字」不必改界面:加 aria-label 就能让语音、自动化、语音控制共用另一个字符串。这是有意的逃逸口,也是最容易在不知情时改写用户所见的地方。名称算完之后才轮到角色和状态被读出——计算本身不管这三者齐不齐。
怎么研究
在开发者工具的无障碍面板里读 Computed Name,不要听一遍口语就下结论。做一组最小控件:只有可见文字;加上 aria-label;再加上 aria-labelledby 指向另一段隐藏文本;只留 title。同一套在 NVDA+Firefox、JAWS+Chrome、VoiceOver+Safari 上听名称字符串,记下与面板是否一致。
自变量:名称来源组合、是否为空字符串、是否指向多个 ID。 因变量:计算名、阅读器实际语音、是否回落到下一个来源。
空的 aria-label="" 会不会阻断回落,各引擎不完全相同,这是要记的分叉,不是可以忽略的边角。
边界
SVG、MathML、表格头、input type="submit" 的默认「提交」各有宿主规则,不能拿按钮那一套优先级当全称命题。aria-labelledby 指向的节点自己又有名称来源时会递归,循环引用会被掐断,结果可能比作者以为的短。隐藏节点能否进入计算,取决于隐藏手法:display:none 与 aria-hidden 在不同步骤被排除。移动端阅读器有时把可见文字和计算名都念一遍,听起来像「没覆盖」,其实是冗余播报策略。
怎么落地
- 给控件起名时先选定一个最高来源并写对,不要同时堆
aria-label、labelledby和可见文字还指望它们相加。 - 需要覆盖可见文字时(图标按钮、可见文字过长、多段合成),显式用
aria-labelledby或aria-label,并在检查器里确认计算名就是那一串。 - 不要留空的
aria-label或指向已删除节点的labelledby去「占位」,它可能阻断回落到可见文字。 - 验证:打开无障碍面板看每一个交互节点的 Computed Name;再用 NVDA 只听名称(不展开描述)。面板里的字符串与语音不一致,或与作者以为的来源不一致,就是优先级被写错或被空值截断。