html全局属性和aria属性必须按语义逻辑组合使用;真正跨元素通用的核心全局属性仅有id、class、data-、title、lang、dir、style、tabindex(需显式设为"0");aria-须配合role或原生语义才生效;hidden与aria-hidden机制不同,不可混用;aria状态必须由js实时同步ui实际状态。

HTML全局属性和ARIA属性不是“加了就可访问”,而是必须按语义逻辑组合使用;单独写aria-label、role="button"或hidden,大概率导致读屏跳过、焦点丢失或状态不同步。
哪些全局属性真正在所有元素上生效
不是标着“全局”的都能乱用。比如contenteditable在<script></script>上无效,hidden放在里浏览器直接忽略——不报错,也不起作用。
真正稳定、跨元素通用的核心全局属性只有这几个:id、class、data-*、title、lang、dir、style、tabindex(注意:布尔值需显式设为tabindex="0"才可聚焦)。
-
aria-*系列虽常被归为全局,但必须配合role或原生语义元素才生效;单独加aria-label到<div>上,读屏器大概率跳过 <li> <code>draggable默认是"auto",不是true;<p></p>默认不可拖,得显式写draggable="true" -
inert在 Chrome 122+、Firefox 125+ 才稳定支持,旧版需降级逻辑 - 给原生
<button></button>加role="button"会覆盖默认语义,在部分旧版 NVDA 中识别为“未知按钮” - 给
<div>加<code>role="button"却不配tabindex="0"和键盘事件监听,会导致键盘不可聚焦、不可触发 <div role="link">比没写更糟:它没有<code>href,无法被键盘跳转,也无法被搜索引擎索引真正需要
role的场景,是封装自定义组件(如树形控件、日历弹层),且必须同步处理焦点流、键盘响应(Enter/Space)、视觉焦点样式和aria-disabled等状态。hidden 和 aria-hidden 混用会破坏可访问性树
hidden和aria-hidden="true"作用机制根本不同,混用等于主动制造冲突。-
hidden让元素从渲染树和可访问性树中**完全移除**,读屏器根本“看不见”它 -
aria-hidden="true"只让辅助技术忽略该节点,但节点仍在 DOM 中、仍可被 JS 操作 - 错误写法:
<div hidden aria-hidden="true">…</div>→ axe 工具直接报错“conflicting visibility attributes”
如果目标是“视觉隐藏 + 读屏也跳过”,只用
hidden就够了;如果目标是“视觉可见但读屏忽略”,只能用aria-hidden="true",且必须确保子元素不含可聚焦控件(否则键盘用户能进、读屏却不知情)。ARIA 状态同步比“显示/隐藏”更重要
读屏是否正确播报,取决于状态属性是否与 UI 实际一致,而不是靠“藏起来再露出来”。
- 下拉菜单展开与否,关键不是
hidden开关,而是aria-expanded值是否实时更新、aria-activedescendant是否指向当前高亮项 -
role="alert"默认启用aria-live="assertive",适合“登录失败”这类需立即干预的场景;非紧急提示(如“已保存”)该用role="status"+aria-live="polite" - 动态插入内容前,建议先清空旧文本再写入新内容,否则某些读屏器会拼接播报(如“已保存已保存”)
最容易被忽略的是:所有 ARIA 状态都依赖 JS 主动更新,静态 HTML 写死一个
aria-expanded="false"而实际 UI 已展开,等于向读屏器撒谎。-
role 属性不能替代原生语义
role不是“增强可访问性”的开关,而是语义缺失时的补救手段;用错比不用更危险。











