必须用 fieldset + legend 实现语义化分组,因 div 包裹会丢失可访问性上下文,屏幕阅读器无法关联标题与控件,wcag 报 fieldset-missing-legend;legend 必须为 fieldset 的直接子节点,不可嵌套 div 或 span,否则语义链断裂;optgroup 仅适用于 select 内部选项归类,与 fieldset 完全无关,不可混用或替代。

必须用 fieldset + legend 实现语义化分组,optgroup 仅适用于 select 内部选项归类,二者不可混用或替代。
为什么不能用 div 包裹 radio/checkbox 来模拟分组
视觉上看似一样,但会彻底丢失可访问性上下文:屏幕阅读器无法将控件与标题关联,WCAG 检查直接报 fieldset-missing-legend;JavaScript 中也无法通过 fieldset.elements 批量获取子项,后续禁用、遍历、验证都得手动写逻辑。
常见错误现象:
-
<div class="group"> <h3>偏好设置</h3> <input type="checkbox" name="theme"> 暗色模式</div>→ 无语义、无批量控制能力 - 用 CSS 边框 +
h3替代legend→ 标题不绑定到组内每个控件,读屏器跳过或重复播报
fieldset 和 legend 的 DOM 位置硬约束
legend 必须是 fieldset 的第一个子节点,中间不能插入任何包装元素(如 div、span),否则语义链断裂。
正确结构:
错误结构(即使样式正常):
原因:辅助技术只识别 fieldset > legend 直接父子关系,嵌套一层 div 就等同于没有 legend。
optgroup 只在 select 内部生效,且不能嵌套
optgroup 是 select 的专属子元素,用于对下拉选项做视觉+语义分组,但它和 fieldset 完全无关,也不能用来包裹 input 或 textarea。
典型用法:
<select name="category"><optgroup label="前端技术"> <option value="html">HTML</option> <option value="css">CSS</option> </optgroup> <optgroup label="后端语言"> <option value="python">Python</option> <option value="go">Go</option> </optgroup></select>
注意点:
-
optgroup的label属性值不可为空,否则部分读屏器静音 -
optgroup不支持禁用整组(disabled只能设在单个option上) - 不能把
input放进optgroup—— 浏览器会忽略或报解析警告
多层分组时的嵌套合理性判断
可以嵌套 fieldset,但必须有清晰的业务层级,否则反而增加认知负担。
合理嵌套示例(注册表单):
不合理嵌套:
- “基本信息”下再套“姓名”“邮箱”两个独立
fieldset→ 过度切分,破坏逻辑聚合 - 用
fieldset包裹单个input→ 无分组意义,纯属冗余 - 同一级多个
fieldset标题语义重叠(如都叫“设置”)→ 用户无法区分意图
真正容易被忽略的是:分组标题(legend)不是装饰文字,它参与表单语义树构建,影响所有自动化测试、无障碍评估和 JS 框架的表单解析逻辑。写错位置或省略,问题不会立刻在浏览器里显现,但会在用户看不见的地方持续失效。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











