单选按钮组无障碍关键三点:name属性必须字面量完全一致;默认选中须用HTML checked属性而非JS设置;网格化多题须用table+aria-labelledby实现语义关联。

单选按钮组必须共用完全一致的 name 属性
name 不匹配是导致屏幕阅读器把单选按钮识别为独立复选框的最常见原因。浏览器只靠 name 相同来建立互斥关系,不依赖 class、id 或 JS 逻辑。
- 错误写法:
<input type="radio" name="theme">和<input type="radio" name="Theme">(大小写不同) - 错误写法:
<input type="radio" name="user[preference]">和<input type="radio" name="user_preference">(格式不统一) - 验证方法:运行
document.querySelectorAll('input[type="radio"][name="theme"]').length,结果应等于预期选项数 - 服务端渲染或静态 HTML 中,所有同组项的
name必须字面量完全相同,不能靠 JS 拼接或模板变量隐式生成
label 关联必须显式用 id + for,不能只靠包裹
虽然 <label><input>文字</label> 能触发点击,但对屏幕阅读器而言,它无法稳定绑定「哪个 label 对应哪个 radio」,尤其在复杂布局或动态插入时。
将 Markdown 文章转换为微信公众号兼容的纯 HTML 格式。当用户要求"转成微信格式"、"生成公众号文章 HTML"、"排版到微信草稿箱"、"微信粘贴格式"时触发。输出带内联样式的纯 HTML,微信编辑器可直接渲染,无需额外适配。支持标题、段落、列表、粗体、行内代码、表格、引用块、代码块、配图的完整转换。
- 正确写法:
<input type="radio" id="theme-dark" name="theme" value="dark">+<label for="theme-dark">深色主题</label> -
for值必须与对应input的id完全一致,包括大小写和连字符 - 避免多个 radio 共用同一个
id,否则for绑定会失效或指向第一个匹配项 - 每个
input都应有唯一id,哪怕视觉上没显示 label 文字(例如表格中靠aria-labelledby组合播报)
默认选中必须用 HTML checked 属性,不能靠 JS 赋值
屏幕阅读器(如 NVDA、VoiceOver)只在初始 DOM 解析阶段读取 checked 属性是否存在,JS 后续设 el.checked = true 不会更新无障碍树中的 aria-checked 状态,也不触发 :checked 伪类的语义映射。
- 正确写法:
<input type="radio" name="size" value="m" checked>(属性存在即生效) - React 中用
defaultChecked,不是checked={true};Vue 中用v-model初始值,而非:checked绑定 - 动态切换时,应通过移除其他同名 radio 的
checked属性(el.removeAttribute('checked'))来模拟,而不是仅设置当前项 - 若服务端无法预知默认值,需在 DOM ready 后用
el.setAttribute('checked', '')补上属性,而非仅改 JS 属性
网格化多题单选必须用 table + aria-labelledby
CSS Grid 或 flex 布局能对齐视觉,但无法向屏幕阅读器传达“第2行第3列 = 问题2、选项+0”这一二维语义。只有 <table> 天然支持行列头关联,再配合 <code>aria-labelledby 才能组合播报。
立即学习“前端免费学习笔记(深入)”;
- 每道题用
<th scope="row" id="q2">Question 2</th>,每个分值用<th scope="col" id="plus0">+0</th> - 每个 radio 写成:
<input type="radio" name="q2" value="0" aria-labelledby="q2 plus0"> -
aria-labelledby引用多个 id 时,屏幕阅读器按 DOM 顺序拼读,所以 id 顺序决定播报语序(建议“问题 id 在前,选项 id 在后”) - 不要给
<table> 加 <code>role="grid"—— 原生<table> 已具备完整语义,加 role 反而可能覆盖默认行为 实际中最容易被忽略的是:name 一致性、checked 的 HTML 属性本质、以及网格场景下对 <code><table> 语义的依赖——这三处出错,屏幕阅读器用户根本无法理解单选组的存在逻辑,更别说完成选择。</table>


















