aria-invalid 和 aria-describedby 必须配对使用,单独设置任一属性均无法让读屏器正确播报错误详情;aria-invalid 只能为 "true" 或省略,aria-describedby 值须严格匹配可见错误文案容器的 id,且该容器需满足可访问性基础要求。

aria-invalid 和 aria-describedby 必须配对使用
单独设 aria-invalid="true" 只会让读屏器播报“无效”,但不会读出错在哪;单独放错误文案而没用 aria-describedby 关联,读屏器根本不会主动读它。两者缺一不可。
常见错误现象:表单提交后输入框变红,键盘用户 Tab 进去只听到“编辑框”,完全不知道哪里错了、该怎么改。
-
aria-invalid只能是"true"或不写(默认"false"),不能写"false"、"1"或空字符串 -
aria-describedby的值必须是错误文案容器的id,且该容器不能用display: none隐藏——得用visibility: hidden+aria-hidden="true"或直接保持 DOM 可见 - 校验通过后,务必同时移除
aria-invalid和aria-describedby,否则旧错误会残留
错误文案容器要满足可访问性基础条件
不是随便塞个 <div> 里写“邮箱格式不对”就行。读屏器要能稳定读到它,这个容器本身就得可访问。
- 必须有明确的
id,且与aria-describedby值严格一致(大小写、连字符、无空格) - 避免嵌套在
display: none父容器中,否则整个子树会被辅助技术忽略 - 文案需为纯文本,避免仅靠图标或颜色传达错误(比如 ❌ + 红字)
- 若错误文案含链接(如“重发验证码”),确保链接本身可键盘聚焦、有
href或role="link"
动态渲染场景下 id 同步容易漏掉
React/Vue 渲染循环表单项时,id 动态生成但 for 或 aria-describedby 没同步更新,是最隐蔽的失效点。
立即学习“前端免费学习笔记(深入)”;
- JS 拼接
id时,检查是否引入了不可见字符(如模板换行、BOM) - 避免用索引当
id(如error-0),推荐用字段名+唯一标识(如error-email-123) - 服务端渲染(SSR)后 JS 再 hydrate,要确认
id在前后端一致,否则首次焦点进入时关联断裂
fieldset + legend 对分组错误更友好
单选/多选类控件出错时,把整组和错误提示一起包裹进 <fieldset>,比逐个绑定更可靠。
-
<legend>会被读屏器作为组名朗读,天然提供上下文(如“请选择您的兴趣领域”) - 错误文案放在
<fieldset>内部、紧邻<legend>后,用aria-describedby指向它,读屏器会连读组名 + 错误 - 不要把
<fieldset>和错误容器拆到不同 DOM 层级,否则部分 AT(如 iOS VoiceOver)可能跳过



















