aria-checked 单独使用无效,必须与 role="checkbox"、tabindex="0" 配合使用;原生 checkbox 不需 aria-checked;自定义需 JS 同步更新 aria-checked 值、视觉样式及键盘事件(Space 键)。

aria-checked 单独写没用,必须配齐三要素
只加 aria-checked="true" 不会让屏幕阅读器把它当复选框读——它压根不知道这是个可交互控件。必须同时满足:role="checkbox"(声明类型)、tabindex="0"(让它能被键盘聚焦)、aria-checked(反映当前状态)。缺一不可。
常见错误现象:div 上写了 aria-checked 但没设 role,读屏器直接跳过;或用了原生 <input type="checkbox"> 却额外加 aria-checked,导致状态双源、不同步。
- 原生
<input type="checkbox">自带完整语义和状态管理,不需要、也不应该手动加aria-checked - 自定义 checkbox(比如用 div + span 模拟)才需要这三要素,且必须用 JS 同步更新
aria-checked值和视觉样式 -
tabindex="0"是硬性要求:没有它,键盘用户按 Tab 根本进不来,Space 键也无法触发切换
为什么不能只靠 checked 属性?
checked 是 HTML 原生属性,只对 <input type="checkbox"> 有效,且仅控制初始状态;它不反映运行时变化,也不被屏幕阅读器主动监听。而 aria-checked 是动态状态标记,专为辅助技术设计,必须由 JS 实时维护。
使用场景:表单中某项需默认选中,但后续逻辑要频繁切换状态(如“全选/取消全选”按钮联动子项),此时 checked 属性无法响应式更新,必须靠 aria-checked 配合 JS 控制。
立即学习“前端免费学习笔记(深入)”;
-
checked="false"在 HTML 中无效——只要checked属性存在,就视为 true -
aria-checked只接受"true"、"false"或"mixed"字符串,不能写布尔值true或数字1 - 混合状态(
"mixed")适用于“半选”场景,比如父级 checkbox 表示部分子项已选,此时视觉和aria-checked都得同步设为"mixed"
监听 Space 键是刚需,不是可选项
即使 DOM 上 aria-checked 值正确,如果没监听 Space 键并手动翻转它,键盘用户就永远无法操作这个复选框。Enter 键不适用——WAI-ARIA 规范明确要求 checkbox 类型控件用 Space 切换。
容易踩的坑:只绑了 click 事件,漏掉 keydown;或者判断了 event.key === 'Enter',结果键盘用户按空格毫无反应。
- 必须监听
keydown事件,检查event.key === ' '(注意是空格字符,不是字符串 'Space') - 触发后要同步更新:
element.setAttribute('aria-checked', newCheckedValue)+ 触发视觉反馈(比如切换 class) - 别忘了
event.preventDefault(),否则空格会滚动页面
和原生 checkbox 混用会出问题
把 aria-checked 加在原生 <input type="checkbox"> 上,等于让两个状态系统打架:一个是浏览器内置的 input.checked,一个是开发者手动维护的 aria-checked。一旦 JS 更新不及时,读屏器读到的和实际勾选状态就不一致。
性能影响几乎为零,但兼容性和可维护性风险很高。尤其在 SSR 或框架渲染场景下,容易出现服务端初始值和客户端状态脱节。
- 正确做法:要么纯原生,靠
input.checked和change事件;要么纯自定义,彻底不用input标签,只用div+role="checkbox"+aria-checked - Bootstrap、Ant Design 等组件库的 checkbox 封装,内部其实都走的是自定义路径,所以它们必须自己管好
aria-checked的同步 - 测试时务必用 NVDA + Firefox 或 VoiceOver + Safari 实测键盘操作流,不能只看 DOM 属性是否更新



















