错误提示必须紧邻后预置dom并用aria-invalid与aria-describedby严格配对绑定,label与input的for/id必须正确关联,更新文案用textcontent,隐藏用visibility: hidden或clip-path,id需字段名+唯一标识,实时用devtools accessibility面板验证。

错误提示必须紧邻 <input> 后插入,且要靠 aria-invalid 和 aria-describedby 配对绑定——只写一个或顺序/ID 错了,屏幕阅读器就完全读不到错在哪。
错误容器必须预置 DOM,不能 JS 动态创建
移动端和部分 AT(如 NVDA)根本不会播报 JS 新增的 <div class="error">。它得在 HTML 加载时就存在,哪怕初始为空。
<ul>
<li>正确写法:<code><input id="phone"><div id="phone-error" role="alert" aria-live="polite"></div>
el.textContent = "手机号格式不对",禁用 innerHTML(XSS + 可访问性树不刷新)display: none 隐藏错误容器——用 visibility: hidden 或 clip-path: inset(100%),否则辅助技术直接忽略整棵树aria-invalid 和 aria-describedby 必须严格配对
单独设 aria-invalid="true",读屏器只会说“无效”,不读内容;单独放错误文案但没用 aria-describedby 指向它,读屏器压根不触发播报。
-
aria-invalid只能是"true"或省略(不能写"false"、""、"1") -
aria-describedby的值必须是错误容器的id,大小写、连字符、空格全部逐字符一致 - 校验通过后,必须同时移除
aria-invalid和aria-describedby,否则旧错误残留
label 和 input 的 for/id 关联是前提,不是可选项
如果 <label for="phone"></label> 和 <input id="phone"> 没对上,错误提示再准也没用——屏幕阅读器连“这是个手机号输入框”都读不出来,更别说错误上下文。
- 动态生成 ID 时(如 React/Vue),确保
htmlFor和id值同步更新,别硬编码字符串 - 避免用索引当 ID(如
error-0),推荐字段名+唯一标识(如error-phone-abc123) - 用 DevTools 的 “Accessibility” 面板实时验证:选中
<label></label>→ 查看 “Name” 是否可读、是否指向正确控件
最常被绕过的点是:错误状态和 DOM 可见性必须耦合控制——你改了 textContent,却忘了同步 visibility;清了 aria-invalid,却漏掉 aria-describedby;甚至把错误容器塞进 display: none 的父级里,整个提示就从可访问性树里消失了。











