aria-required="true" 仅向屏幕阅读器声明必填语义,不参与浏览器校验;required 触发原生验证和键盘优化,两者需共存以兼顾可访问性与功能。

aria-required="true" 不是必需的,但它是必要的补充——它不改变浏览器校验行为,只告诉屏幕阅读器“这个字段不能跳过”。
aria-required 和 required 属性到底谁管什么?
required 是浏览器原生验证的开关:它触发提交拦截、影响移动端键盘类型(比如 type="email" 自动唤出 @ 键),但对辅助技术无显式语义表达。而 aria-required 是纯语义声明,不参与任何校验逻辑,只被 NVDA、JAWS、VoiceOver 等读屏软件识别并朗读为“必填”。
两者不是互斥关系,而是分工明确:
- 写了
required但没写aria-required="true"→ 视障用户可能完全不知道这是必填项 - 只写
aria-required="true"但没写required→ 浏览器不会阻止空提交,表单逻辑失效 - 两者都写 → 原生校验 + 辅助技术可读,WCAG 合规性达标
为什么 label:required::after 加星号还不够?
视觉上的 * 对色盲、低视力或仅用键盘导航的用户无效。更关键的是:label:required::after 只匹配带 required 的 label 元素本身,而大多数表单结构中 label 并不直接带该属性(它是 input 上的)。
常见错误写法:
<label for="name">姓名</label> <input id="name" name="name" required>
上面的 label 没有 required,所以 label:required::after 根本不生效。正确做法是:
- 用
label:has(input:required)::after(现代浏览器支持,需注意 Safari 15.4+) - 或给
label手动加 class,如<label class="required"></label>,再配 CSS - 但无论哪种,都必须同步确保
input有required和aria-required="true"
自定义组件里 aria-required 容易漏传
在 Vue/React 封装的输入框中,required 属性常被当成普通 prop 透传到内部 input,但 aria-required 往往被忽略——尤其当组件内部用 div 包裹或使用非原生标签时。
典型问题场景:
- 组件接收
:required="true",但没把aria-required="true"写进最终渲染的input标签 - 用
role="textbox"替代原生input,却没补aria-required - 动态控制必填状态(如根据条件切换),但只改了 JS 变量,没同步更新 DOM 属性
验证方法很简单:打开 Chrome DevTools → Elements 面板 → 找到实际渲染的 input → 检查是否同时存在 required 和 aria-required="true"。
旧版 IE 和部分 JAWS 版本需要显式声明
IE11 不支持 aria-required,但它支持原生 required,所以对 IE 用户影响有限。真正要小心的是某些老旧版本的 JAWS(如 2018 以前),它们对原生 required 的识别不稳定,会跳过该字段的“必填”提示。
因此,在企业级表单或政务类系统中,即使你已写 required,也建议坚持加上 aria-required="true" ——这不是冗余,而是兼容性兜底。
容易被忽略的一点:不要给非必填项写 aria-required="false"。这反而会让读屏软件误判,WCAG 明确反对这种写法。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











