ARIA属性是语义断层的显性标记,暴露原生HTML失效;role="button"警示冒充控件与键盘交互缺失;aria-live须静态声明于初始DOM;lang必须用IETF标准值如zh-CN;表格需scope或headers确保可读性。

aria- 属性不是补丁,而是语义断层的显性标记——只要代码里大量出现 role、aria-label、aria-hidden,基本说明原生 HTML 结构已失效。
为什么 role="button" 是危险信号
它暴露了两个根本问题:用了 div 或 span 冒充可交互控件;没处理键盘事件(Enter/Space)和焦点状态(tabindex)。屏幕阅读器虽能读出“按钮”,但用户按空格却无响应,或焦点卡死,体验直接断裂。
- 优先替换为
<button>—— 它自带type="button"、可聚焦、可提交、支持所有键盘操作 - 若必须用非原生元素(如 SVG 图标按钮),至少补全:
tabindex="0"+role="button"+onclick和onkeydown双事件监听 - 禁止写
role="button"却不设tabindex—— 这类元素对键盘用户完全不可达
aria-live 区域必须绑定真实 DOM 节点
常见错误是把 aria-live 加在 JS 动态插入的临时容器上,比如 document.createElement('div') 后直接 appendChild。一旦该节点被后续 DOM 操作移除(如 React 重渲染、Vue v-if 切换),通知就彻底丢失。
- 必须在初始 HTML 中静态声明,例如:
<div aria-live="polite" id="live-region"></div> - 更新时只改
textContent或innerText,避免innerHTML—— 后者可能触发额外 DOM 解析,干扰屏幕阅读器播报节奏 -
aria-live="assertive"仅用于紧急中断(如表单验证失败),否则会打断用户当前操作
lang 属性错写等于语言乱码
写成 lang="zh" 或 lang="cn",NVDA、VoiceOver 就会把中文内容按日语或英语发音规则朗读,分词错、声调崩、语义失真。这不是“差不多就行”,是直接让听障用户无法理解内容。
立即学习“前端免费学习笔记(深入)”;
- 严格使用 IETF 标准值:
lang="zh-CN"(简体)、lang="zh-TW"(繁体)、lang="zh-HK"(港台) - 必须出现在根
<html>标签上,不能靠 JS 动态设置 —— 屏幕阅读器启动时就读取该属性,晚于首屏渲染即无效 - 局部语言切换用嵌套:
<p lang="en">Hello</p>,而非全局覆盖
表格缺失 scope 或 headers 就等于数据不可读
屏幕阅读器读表格时,默认只报单元格内容,不报行列关系。没有 scope="col" 或 headers 关联,用户听到的就是一串孤立数字:“123”、“456”、“789”……完全无法判断哪列是“姓名”、哪列是“电话”。
- 表头单元格必须明确标注:
<th scope="col">姓名</th>或<th scope="row">张三</th> - 复杂表(多级表头)必须用
headers属性指向对应id:<td headers="name age">张三</td> - 禁止用
<div>模拟表格 —— 即使加了role="table",也缺乏原生表格的导航键支持(如 Ctrl+Alt+方向键)
真正难的不是写对某条 ARIA 属性,而是持续克制“用 JS 模拟一切”的冲动——每多一个 role,就少一分语义确定性;每绕开一个原生标签,就多一层兼容性风险。质量核准的本质,是确认 HTML 是否在尽可能少依赖 ARIA 的前提下,仍能让辅助技术准确还原意图。



















