aria-checked不能用于原生checkbox,否则导致状态撕裂;仅适用于自定义复选框(如),需配合tabindex、键盘事件及js同步更新。

aria-checked不能用在原生上
浏览器会自动同步原生复选框的 aria-checked 状态,手动设置反而会导致读屏器播报错乱。比如你写 <input type="checkbox" aria-checked="true">,但实际未勾选,屏幕阅读器会说“已选中”,而视觉和行为却是未选中——状态撕裂。
真正需要 aria-checked 的场景,是**完全自定义的、非原生的复选框**,比如用 <div role="checkbox"> 实现的控件。此时必须手动管理:
<ul>
<li>用 <code>role="checkbox" 声明语义,否则读屏器根本不知道这是个可切换项
aria-checked="false" 或 "true",不能省略aria-checked 属性值aria-labelledby 或 aria-label 关联的文本,确保状态变更被播报原生复选框无障碍靠
对标准 <input type="checkbox">,无障碍的关键是:
-
<label for="id"></label>必须存在且for与id严格匹配(大小写敏感) - 不要用
aria-labelledby替代真实<label></label>——它不触发表单提交,也不参与原生 focus 流程 - 视觉隐藏原生控件时,用
position: absolute; opacity: 0; width: 1px; height: 1px;,而非display: none或visibility: hidden - 焦点样式用
:focus-visible而非:focus,避免鼠标用户看到冗余轮廓
浏览器会自动暴露 checked 状态给辅助技术,无需、也不应干预 aria-checked。
自定义复选框用role="checkbox"时,aria-checked必须配合tabindex和键盘事件
仅加 role="checkbox" 和 aria-checked 不够,键盘用户无法操作。必须:
- 设
tabindex="0"让元素可聚焦 - 监听
keydown,对Space键调用event.preventDefault()并翻转状态 - 状态变更后,同步更新
aria-checked值,并可选触发aria-live区域播报(仅当需额外提示时) - 禁用状态下,加
aria-disabled="true"并移除tabindex,否则键盘仍能聚焦但无响应
漏掉任一环节,键盘用户就卡住——比如按空格没反应,或焦点进不去,或状态变了但读屏器没说。
容易踩的坑:把aria-checked加在label或span上
常见错误是把 aria-checked 放在包裹复选框的 <label></label> 或 <span></span> 上,例如:
<label aria-checked="false"><input type="checkbox"> 我同意</label>
这毫无意义:aria-checked 只对带 role="checkbox" 的元素生效;<label></label> 本身没有该语义,读屏器直接忽略该属性。更糟的是,它可能干扰 label 的正常播报逻辑。
真正要控制的,永远是那个承担 checkbox 行为的元素本身——要么是原生 <input>(此时不用管 aria-checked),要么是你自己实现的 <div role="checkbox">(此时必须管)。</div>











