原生语义标签比ARIA更可靠;缺乏键盘支持和表单行为,应优先用;有可见文本用aria-labelledby,纯图标用aria-label;aria-live="polite"用于状态提示,assertive用于关键错误;Font Awesome装饰性图标自动aria-hidden="true",功能性图标需显式声明语义。

原生语义标签比 ARIA 更可靠,能直接被屏幕阅读器识别;ARIA 是补救手段,不是替代方案。
为什么不能用 替代 浏览器对 有内置键盘支持(Enter/Space 触发)、焦点管理、表单提交行为和隐式 role="button";而 只告诉读屏器“这是按钮”,但没实现键盘响应、焦点进入逻辑或表单关联——用户按 Tab 能聚焦,却无法用空格触发,或提交时被忽略。常见错误现象:
- 自定义按钮在 VoiceOver 下朗读为“按钮”,但按 Space 无反应
- 表单中用
提交,form.submit() 不触发,且 Lighthouse 报“交互元素缺少键盘支持”
正确做法是:优先用 ;若必须用非按钮元素(如图标区域),需手动加 tabindex="0"、监听 keydown(捕获 Enter/Space)、并同步维护 aria-pressed 或 aria-expanded 状态。
aria-label 和 aria-labelledby 到底该写哪个?
两者都提供可访问名称,但更新机制和维护成本完全不同:aria-labelledby 指向页面中已存在的可见文本节点(如 ),内容随 UI 变更自动同步;aria-label 是硬编码字符串,一旦文案改了或切换语言,就立刻失效。
典型踩坑点:
- 给搜索框写
aria-label="Search",UI 后来改成中文“查找”,读屏器仍念英文
- 同时写
aria-label 和 aria-labelledby,后者被完全忽略,且 axe 工具报错
- 用
aria-label 描述图标按钮,但图标旁已有文字“设置”,造成重复朗读
建议规则:
- 有对应可见文本 → 用
aria-labelledby="id"
- 纯图标、加载 Spinner、隐藏操作区 → 用
aria-label
- 绝对不要共存
动态列表更新时,aria-live 怎么设才不打断用户?
aria-live 控制读屏器是否播报 DOM 变更,但 politeness 值选错会导致语音流崩溃:assertive 强制中断当前朗读,polite 等空闲时播报,off 完全静默。
list.js 类场景常见错误:
- 整个搜索结果容器设
aria-live="assertive",用户每输一个字,读屏器就插话“正在搜索…”,根本没法听清提示
- 错误消息区域用了
polite,结果“邮箱格式错误”被延迟 5 秒才读出,用户早点了提交
- 把
aria-live 加在
上,但 list.js 内部用 innerHTML 替换整个列表,导致读屏器丢失上下文、只读新内容不报数量变化
实操建议:
- 搜索状态提示(如“找到 3 条结果”)用
aria-live="polite",包裹最小节点(如仅 )
- 关键错误(如“登录失败:账号不存在”)用
aria-live="assertive",且配合 role="alert"
- 避免对整块区域设
aria-live,尤其不要套在 list.js 的根容器上
Font Awesome 图标要不要加 ARIA?怎么加?
Font Awesome 7 会自动检测:如果图标没任何标签属性(aria-label、aria-labelledby、title、role),就默认加 aria-hidden="true" —— 这意味着:装饰性图标不用管,它已帮你处理好。
但功能性图标必须显式声明语义,否则读屏器要么跳过,要么读成“图形”:
- 导航菜单图标(☰)→ 加
aria-label="打开侧边栏"
- 搜索放大镜 → 加
aria-label="搜索" 或关联 aria-labelledby="search-label"
- 状态图标(✅)→ 若旁边无文字,必须加
aria-label="操作成功";若有“已保存”文字,则图标应保持 aria-hidden="true"
容易被忽略的一点:aria-hidden="true" 具有继承性——父元素设了它,子元素即使写 aria-hidden="false" 也无效。所以别在模态框外层 上乱加这个属性,该用 inert 或焦点锁定代替。
浏览器对 常见错误现象: 正确做法是:优先用 两者都提供可访问名称,但更新机制和维护成本完全不同: 典型踩坑点: 建议规则: list.js 类场景常见错误: 实操建议: Font Awesome 7 会自动检测:如果图标没任何标签属性( 但功能性图标必须显式声明语义,否则读屏器要么跳过,要么读成“图形”: 容易被忽略的一点: 有内置键盘支持(Enter/Space 触发)、焦点管理、表单提交行为和隐式 role="button";而
,form.submit() 不触发,且 Lighthouse 报“交互元素缺少键盘支持”;若必须用非按钮元素(如图标区域),需手动加 tabindex="0"、监听 keydown(捕获 Enter/Space)、并同步维护 aria-pressed 或 aria-expanded 状态。
aria-label 和 aria-labelledby 到底该写哪个?aria-labelledby 指向页面中已存在的可见文本节点(如 ),内容随 UI 变更自动同步;aria-label 是硬编码字符串,一旦文案改了或切换语言,就立刻失效。
aria-label="Search",UI 后来改成中文“查找”,读屏器仍念英文aria-label 和 aria-labelledby,后者被完全忽略,且 axe 工具报错aria-label 描述图标按钮,但图标旁已有文字“设置”,造成重复朗读
aria-labelledby="id"
aria-label
动态列表更新时,
aria-live 怎么设才不打断用户?aria-live 控制读屏器是否播报 DOM 变更,但 politeness 值选错会导致语音流崩溃:assertive 强制中断当前朗读,polite 等空闲时播报,off 完全静默。
aria-live="assertive",用户每输一个字,读屏器就插话“正在搜索…”,根本没法听清提示polite,结果“邮箱格式错误”被延迟 5 秒才读出,用户早点了提交aria-live 加在 上,但 list.js 内部用 innerHTML 替换整个列表,导致读屏器丢失上下文、只读新内容不报数量变化
aria-live="polite",包裹最小节点(如仅 )aria-live="assertive",且配合 role="alert"
aria-live,尤其不要套在 list.js 的根容器上Font Awesome 图标要不要加 ARIA?怎么加?
aria-label、aria-labelledby、title、role),就默认加 aria-hidden="true" —— 这意味着:装饰性图标不用管,它已帮你处理好。
aria-label="打开侧边栏"
aria-label="搜索" 或关联 aria-labelledby="search-label"
aria-label="操作成功";若有“已保存”文字,则图标应保持 aria-hidden="true"
aria-hidden="true" 具有继承性——父元素设了它,子元素即使写 aria-hidden="false" 也无效。所以别在模态框外层 上乱加这个属性,该用 inert 或焦点锁定代替。











