在前端开发中,aria-label 常被用作提升可访问性的快捷方式。然而,一个普遍存在的反模式是将其滥用于 <div>、<span> 等通用容器元素上。这种做法不仅无法改善无障碍体验,反而会污染可访问性树(accessibility tree),造成屏幕阅读器用户的困惑。
问题的本质:语义与命名的错位
HTML 规范中,<div> 和 <span> 被定义为通用容器元素(generic elements),它们本身不承载任何语义信息,仅用于布局或样式包裹。当开发者给这些元素添加 aria-label 时,实际上是在尝试为 "无意义" 的容器赋予 "有意义" 的名称。
根据 WAI-ARIA 规范,aria-label 和 aria-labelledby 只能用于具有隐式或显式 ARIA 角色的元素,且该角色不能标记为 "Name prohibited"。通用元素如 <div> 和 <span> 默认没有可访问性角色,因此为它们添加标签在规范层面就是无效的。
更深层的问题是浏览器和辅助技术的处理方式。不同浏览器对通用元素上的 aria-label 支持不一致,屏幕阅读器可能完全忽略这些标签,或者将其错误地暴露为可交互节点。这种不确定性导致了 "视觉呈现与辅助技术体验" 的割裂 —— 明眼用户看到的是一个普通容器,而屏幕阅读器用户可能听到一个突兀的、脱离上下文的标签名称。
可访问性树污染的具体表现
当 aria-label 被错误地应用于通用元素时,会产生以下几种负面影响:
1. 节点噪声增加 可访问性树会被大量无意义的命名节点填充。这些节点没有实际交互功能,却占据了屏幕阅读器的导航路径,用户不得不逐个跳过才能到达真正重要的内容。
2. 子内容被遮蔽
如果 <div aria-label="关闭">×</div> 这样的代码存在,屏幕阅读器可能只读出 "关闭" 而忽略其中的 "×" 符号。对于依赖屏幕阅读器的用户,他们无法感知视觉上的关闭按钮样式。
3. 翻译与维护隐患
aria-label 中的文本不会被大多数翻译服务自动处理,这导致多语言网站中辅助技术用户获得的信息可能与视觉文本不一致。此外,硬编码的标签字符串与可见文本分离,增加了维护时信息不同步的风险。
哪些元素可以合法使用 aria-label
理解 "不能用" 之后,需要明确 "可以用" 的范围。根据 HTML-Validate 等工具的检测规则,以下元素类别允许使用 aria-label 或 aria-labelledby:
- 交互元素:
<button>、<a>、<input>、<select>、<textarea>等 - 可标记元素:表单控件及其关联标签
- 地标元素:
<nav>、<main>、<aside>、<header>、<footer>、<section>等 - 特定角色元素:继承自 widget 角色的自定义组件
- 特殊元素:
<area>、<dialog>、<form>、<fieldset>、<iframe>、<img>、<figure>、<summary>、<table>及其子元素
对于自定义组件(Web Components),如果需要在组件上暴露 aria-label,必须在组件的元数据中显式声明该属性,否则同样会被视为误用。
常见误用模式与修复方案
模式一:用 div 模拟按钮
<!-- 错误 -->
<div aria-label="关闭对话框" onclick="close()">×</div>
<!-- 正确 -->
<button type="button" aria-label="关闭对话框">×</button>
修复要点:使用原生 <button> 元素不仅解决了 aria-label 的合法性问题,还自动获得了键盘可访问性(Tab 导航、Enter/Space 触发)和焦点管理。
模式二:给 span 添加描述性标签
<!-- 错误 -->
<span aria-label="用户头像">
<img src="avatar.png" alt="">
</span>
<!-- 正确 -->
<img src="avatar.png" alt="用户头像">
修复要点:图片的替代文本应该直接放在 alt 属性中,而非包裹元素的 aria-label 上。
模式三:为表单区域添加标签
<!-- 错误 -->
<div aria-label="个人信息">
<input placeholder="姓名">
<input placeholder="电话">
</div>
<!-- 正确 -->
<fieldset>
<legend>个人信息</legend>
<label for="name">姓名</label>
<input id="name" type="text">
<label for="phone">电话</label>
<input id="phone" type="tel">
</fieldset>
修复要点:表单分组应使用 <fieldset> 配合 <legend>,单个字段应使用 <label> 进行显式关联。
工程化检测方案
在团队开发中,依靠代码审查来发现 aria-label 误用效率低下。推荐在 CI/CD 流程中集成自动化检测:
HTML-Validate 配置
{
"rules": {
"aria-label-misuse": "error"
}
}
该规则会标记所有在不允许的元素上使用 aria-label 或 aria-labelledby 的情况,包括 <div>、<span>、<p> 等通用元素。
ESLint 插件
使用 eslint-plugin-jsx-a11y 可以检测 JSX 中的类似问题:
{
"rules": {
"jsx-a11y/aria-props": "error",
"jsx-a11y/aria-role": "error"
}
}
浏览器 DevTools 验证
Chrome DevTools 的 "完整可访问性树" 视图可以直观展示哪些元素被错误地命名。打开 DevTools → Accessibility 面板,检查是否存在无交互功能的命名节点。
实践检查清单
在代码审查或重构时,使用以下清单快速识别和修复问题:
- 语义优先原则:需要
aria-label时,先问自己 " 这个元素是否应该用<button>、<a>、<nav>等语义元素替代 " - 交互元素白名单:确认目标元素是否在允许使用
aria-label的列表中 - 可见文本优先:如果标签内容在页面上可见,使用
aria-labelledby引用可见文本的 ID,而非重复的aria-label - 原生标签优先:表单字段优先使用
<label>元素进行显式关联,而非aria-label - 自动化门禁:在提交前运行 HTML-Validate 或类似工具,将
aria-label-misuse设为错误级别规则
结论
aria-label 是强大的无障碍工具,但必须在正确的语义上下文中使用。将其应用于 <div>、<span> 等通用元素不仅违反规范,还会造成可访问性树污染和用户体验不一致。解决之道在于回归语义化 HTML—— 当需要为元素命名时,首先选择具有正确隐式角色的原生元素,只有在原生方案不可行时才谨慎使用 ARIA。记住 WAI-ARIA 的第一原则:如果可以用原生 HTML 元素实现,就不要使用 ARIA。
参考来源
- Scott O'Hara: Name, labels, ARIA, what to do?
- HTML-Validate: Disallow aria-label and aria-labelledby misuse
内容声明:本文无广告投放、无付费植入。
如有事实性问题,欢迎发送勘误至 i@hotdrydog.com。