纯图标按钮必须加 aria-label 且置于 button 标签上,同时 svg 需设 aria-hidden="true";有可见文字时优先用 aria-labelledby;aria-label 不可滥用,禁用空字符串。

纯图标按钮不加 aria-label 就等于没功能
屏幕阅读器遇到 <button><svg></svg></button> 这类无文字按钮,只会朗读“按钮”或“未命名按钮”,用户完全不知道点它会触发什么操作。这不是体验问题,是 WCAG 4.1.2 明确要求的可访问性底线——必须让控件有可识别的名称。
必须把 aria-label 加在 <button> 上,而不是里面的 <svg>。写错位置等于白加:
-
<button aria-label="删除"><svg aria-hidden="true"></svg></button>✅ 正确 -
<button><svg aria-label="删除" aria-hidden="true"></svg></button>❌aria-label被忽略
<svg> 必须同步加 aria-hidden="true",否则某些读屏器可能误读路径描述,造成干扰性重复播报。
aria-label 和 aria-labelledby 到底该用哪个
判断标准就一条:页面上有没有现成的、可见的、语义匹配的文字?
立即学习“前端免费学习笔记(深入)”;
- 有——比如图标旁写着“保存”,那就用
aria-labelledby="save-text",指向那个<span id="save-text">保存</span> - 没有——比如模态框右上角的 × 按钮、树节点折叠箭头,才用
aria-label="关闭"或aria-label="展开子节点"
两者不能共存:aria-labelledby 优先级更高,aria-label 会被静默忽略。写了也白写,调试时很难发现。
中文文案要控制在 20 字以内,避免全角空格、零宽字符、省略号——VoiceOver 会截断或报“空白”。
这些地方加 aria-label 反而坏事
aria-label 是覆盖式替代,一加就吃掉内部所有文本。很多“无障碍补救”实际是破坏:
-
<button aria-label="提交">发送</button>→ 屏幕阅读器只读“提交”,“发送”被静音 -
<input id="email">已有<label for="email">邮箱地址</label>,再加aria-label会让<label>形同虚设,Lighthouse 直接报错 -
<img src="logo.png" aria-label="公司标志">→ 错!必须用alt,混用会导致重复朗读或图像被跳过 -
<div aria-label="主菜单"><ul>...</ul></div>→ 无效!<div>默认不可聚焦,读屏器直接跳过;真要用,得配role="navigation"+tabindex="0",但这暴露的是语义缺陷
特别注意:aria-label=""(空字符串)不是“没标签”,而是明确告诉读屏器“这个可操作元素请彻底忽略”——等于把交互入口对视障用户封死。
按钮类交互元素的最小无障碍组合
一个能被键盘 Tab 到、Enter/Space 触发、且被读屏准确识别的按钮,至少需要三要素:
- 语义正确:优先用
<button>,不用<div onclick>或<a href="#"> - 名称可达:无可见文字时,必须配
aria-label或aria-labelledby - 状态同步:如果按钮有禁用逻辑,用原生
disabled属性,别靠 CSS 隐藏 +aria-disabled="true"补救
复杂组件(如自定义开关、下拉菜单)不能只靠 aria-label 解决问题——它们需要完整角色(role)、状态(aria-checked、aria-expanded)和键盘事件支持。这时候加 aria-label 只是第一步,不是终点。



















