必须用 fieldset 包裹同组 checkbox 并配 legend,name 需带[]才被后端识别为数组;disabled fieldset 会使内部控件完全失效;iOS Safari 中 legend 默认不响应点击。

用 fieldset 包住多组 input[type="checkbox"] 才算真正分组
浏览器只认语义结构,光靠 CSS 或 class 名称无法让多选框在逻辑上归属同一组。必须用 fieldset 把一组复选框包裹起来,再配合 legend 标明用途,才能被屏幕阅读器识别、被表单提交逻辑正确聚合。
常见错误是直接把所有 checkbox 并列写在 form 里,结果:提交时 name 相同但缺乏上下文;无障碍工具无法区分“兴趣爱好”和“通知偏好”这两组;JS 获取值时容易漏掉分组意图。
-
fieldset是语义容器,不是样式盒子 —— 不要只为了加边框才用它 - 每组必须有且仅有一个
legend,放在fieldset开头,不可省略 - 所有同组
input的name应保持一致(如name="topic[]"),否则后端收不到数组 - 如果某组只需视觉分组而无需语义分组(比如纯展示),改用
div+ CSS 更合适
后端接收多选值时,name 必须带方括号 []
HTML 表单默认把同名的多个 checkbox 当作单个值覆盖处理,除非显式声明为数组。不加 [],PHP/Node.js/Django 等框架通常只收到最后一个勾选项。
典型错误现象:console.log(new FormData(form)) 显示只有一项;PHP 中 $_POST['hobby'] 是字符串而非数组;Django 视图里 request.POST.getlist('hobby') 返回空列表。
立即学习“前端免费学习笔记(深入)”;
- 正确写法:
<input type="checkbox" name="hobby[]" value="reading"> - PHP 自动转成数组,
$_POST['hobby']是['reading', 'coding'] - Node.js +
express.urlencoded()同样支持,但需确保extended: true - 注意:
name="hobby"和name="hobby[]"是两个完全不同的字段名,别混用
fieldset 被禁用时,内部所有 input 会自动失效
这是 fieldset 最容易被忽略的副作用:给 fieldset 加 disabled,比逐个设 input disabled 更省事,但也更“彻底”——连 legend 文字都会变灰,且整个区域失去焦点和交互能力。
常见误用场景:想临时禁用某组但保留其他组可操作;或误以为 disabled 只影响提交,其实它还会阻止 JS 绑定事件(如 click)。
- 若只需视觉禁用但保留 JS 控制权,改用
fieldset[aria-disabled="true"]+ CSS 模拟 - 若要提交时忽略该组,不要用
disabled,改用display: none或移除name属性 - 注意:被
disabled的fieldset内部input值不会出现在FormData中,也无法通过form.elements访问
移动端 Safari 对 legend 的点击穿透有兼容性问题
在 iOS Safari 上,legend 元素默认不响应点击事件,哪怕你写了 onclick 或绑了 addEventListener('click'),也可能不触发。这不是 bug,是它的默认行为:legend 本身不是交互控件,只是说明文字。
常见错误是试图点击 legend 来全选/反选该组 checkbox,结果在 iPhone 上完全没反应。
- 解决办法:给
legend加role="button"+tabindex="0",并手动处理键盘回车/空格 - 更稳妥的做法:不在
legend上放交互逻辑,另加一个按钮(如“全选”)放在legend旁 - 别依赖
legend:hover做悬停效果,iOS Safari 不支持伪类触发
name 少了那对方括号。











