原生表单控件无需手动设置aria-checked,浏览器自动管理;仅自定义复选框/单选按钮需JS同步维护aria-checked值(true/false/mixed),且mixed仅用于有子项状态汇总的层级结构。

aria-checked 在原生表单控件中根本不需要手动设置
浏览器自动管理 input[type="checkbox"] 和 input[type="radio"] 的 aria-checked 状态,你硬加反而可能干扰辅助技术读取。只要确保 HTML 结构合法、checked 属性或 checked DOM 属性正确同步,屏幕阅读器就能准确播报“已勾选”或“未勾选”。
常见错误:用 div 模拟复选框,却只加 role="checkbox" 却忘了同步控制 aria-checked 值;或者在真实 input 上冗余写 aria-checked="true",导致属性冲突(比如 DOM 中 checked 为 false,但 aria-checked 为 true)。
- ✅ 正确做法:对原生控件,删掉所有手写的
aria-checked - ❌ 错误做法:给
<input type="checkbox">加aria-checked="false" - ⚠️ 注意:
aria-checked是“可选的”而非“推荐的”——WAI-ARIA 规范明确说明它仅用于非原生可交互元素
自定义 checkbox/radio 必须手动同步 aria-checked
当你用 div + span + JS 实现视觉复选框时,必须同时维护两个状态:UI 样式(如添加 .checked 类)和语义状态(aria-checked)。漏掉后者,视障用户将无法感知当前是否选中。
关键逻辑不是“点击就设 aria-checked="true"”,而是要严格跟随控件的选中语义模型:
立即学习“前端免费学习笔记(深入)”;
- 复选框(
role="checkbox"):值只能是"true"、"false"或"mixed"(三态) - 单选按钮(
role="radio"):同一组内仅一个可为"true",其余必须为"false" - 必须用 JS 同步更新
aria-checked,不能只改 class 或文本
示例(简化):
<div role="checkbox" tabindex="0" aria-checked="false"> <span class="custom-checkbox-icon"></span> 我同意条款 </div>
点击后需执行:
el.setAttribute('aria-checked', el.getAttribute('aria-checked') === 'true' ? 'false' : 'true');
aria-checked="mixed" 只用于三态复选框,且有严格前提
aria-checked="mixed" 不是“半选”UI 效果的装饰属性,而是语义上表示“子项部分选中”。它只应在层级结构中使用(如树形菜单、文件夹多选),且必须满足:父节点本身不可直接被用户勾选,仅反映子节点状态汇总。
典型误用场景:
- 给平级的独立复选框设
mixed(无意义,应为true/false) - 没实现子项状态追踪,仅靠 CSS 画个横线就标
mixed(语义失真) - 在单选组里使用
mixed(role="radio"不支持该值)
正确前提:
- 父容器有
role="treeitem"或明确嵌套关系 - 子复选框全部为原生
input或已正确实现aria-checked - JS 主动计算子项状态:全选 →
"true";全不选 →"false";否则 →"mixed"
不要用 aria-checked 替代 CSS :checked 伪类
aria-checked 是给辅助技术读的,不影响样式。很多开发者试图用 [aria-checked="true"] 写 CSS,这不仅冗余(原生控件有 :checked),而且在自定义控件中还容易出竞态:JS 还没来得及设 aria-checked,CSS 就已尝试匹配。
更可靠的做法:
- 原生控件:无条件用
input:checked + .icon或input[type=checkbox]:checked::before - 自定义控件:统一用 class 控制样式(如
.is-checked),JS 更新 class 和aria-checked一起做 - 避免混合使用:比如 class 控制 UI,又额外监听
aria-checked做动画——既增加复杂度,又无实际收益
最易被忽略的一点:当用 JS 切换原生 input.checked = true 时,:checked 伪类会立即生效,但如果你靠监听 aria-checked 来触发样式,就会延迟一帧甚至失效。


















