给纯图标按钮加aria-label是最直接有效的做法,需置于等可交互元素上,值为动词导向的语义短语如"delete item",同时svg或字体图标须加aria-hidden="true"。

给纯图标按钮加 aria-label 是最直接有效的做法
当按钮里只有 <svg></svg> 或字体图标,没有可见文字时,屏幕阅读器默认读不出功能含义。只加 title 属性是无效的——它不被所有读屏软件识别,且在触摸设备上完全不触发。
正确做法是在按钮上直接加 aria-label,值必须是动词导向、语义明确的短语:
- ✅
aria-label="Delete item"(动作 + 对象) - ❌
aria-label="trash icon"(描述图标本身,非功能) - ❌ 同时存在可见文字和
aria-label(会导致重复朗读或覆盖) - ⚠️ 不要用于已有文本内容的按钮,比如
<button><svg></svg> 删除</button>——此时应靠视觉文本+aria-hidden="true"隐藏图标
SVG 独立使用时优先用 role="img" + 内部 <title></title>
如果 <svg></svg> 是作为装饰性以外的独立图标出现(比如页头的 Logo、状态提示图标),规范做法是设 role="img",并在其内部第一个子元素位置放 <title></title>。
注意几个硬性约束:
-
<title></title>必须是<svg></svg>的第一个或第二个子元素(若前面有<desc></desc>);写在后面会被部分读屏器忽略 - 不能写成 HTML 的
<title></title>(那是页面标题) - 避免同时加
aria-label——两者冲突时行为不可预测 - 如果该 SVG 有交互(如点击跳转),还需手动加
tabindex="0"并监听键盘事件
字体图标必须配 aria-hidden="true" + 外部文本或 aria-label
像 <i class="fas fa-user"></i> 这类字体图标本质是 Unicode 字符,无任何语义。直接加 aria-label 到 <i></i> 上是错误的,因为该元素不是语义化容器。
标准解法分两种场景:
- 按钮内含字体图标 + 可见文字:给
<i></i>加aria-hidden="true",文字本身已提供语义 - 纯图标按钮(无文字):给外层按钮加
aria-label,同时确保<i></i>有aria-hidden="true",防止被重复读出 - 绝对不要给
<i></i>加role="img"或aria-label——它不是合法的可访问角色载体
避免用 <img src="icon.svg"> 承载功能性图标
虽然 <img> 支持 alt,但 SVG 作为 src 引入时,内部结构完全不可访问,<title></title> 和 <desc></desc> 全部失效。这意味着你只能靠 alt 提供扁平描述,无法支持动态颜色、状态变化或局部聚焦。
更严重的问题是:一旦图标需响应深色模式、高对比度模式或用户系统偏好,<img> 方式基本无解。而内联 SVG 可以用 currentColor、@media (forced-colors: active) 等原生机制无缝适配。
所以除非是静态装饰图,否则功能性图标别走 <img> 路线。真正容易被忽略的是:很多团队把 Lucide 或 Heroicons 的 CDN 脚本引入后,直接用 <icon name="x"></icon> 组件,却没检查它最终是否渲染为内联 SVG —— 如果底层是 <img>,那所有可访问性努力都白费。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











