legend必须是fieldset的第一个子元素,这是HTML规范强制要求,DOM顺序决定语义绑定,屏幕阅读器依赖此顺序将legend作为整组控件的可访问名称播报。

legend必须是fieldset的第一个子元素
不是“建议”,是 HTML 规范强制要求。DOM 顺序决定语义绑定:屏幕阅读器(如 NVDA、VoiceOver)靠这个顺序把 legend 文本作为整组控件的可访问名称来播报。位置错,等于没写。
常见错误包括:
-
<fieldset><input name="zip"><legend>地址</legend></fieldset>——legend不是首子节点,旧版 Safari 可能完全不识别 -
<fieldset><div><legend>支付方式</legend></div><input type="radio"></fieldset>——legend被包裹,读屏器跳过,只报“单选按钮” - React 中用
Fragment或条件渲染(如{show && <legend></legend>})插在legend前面,导致它不再是直接子节点
正确写法就是:<fieldset><legend>配送时间偏好</legend><input name="time"></fieldset>,纯文本,无空格、无注释、无嵌套标签。
每组fieldset至少包含一个可聚焦的表单控件
fieldset 需要“被激活”才有完整语义。只包提示文字、<p> 或 <div>,浏览器可能忽略其分组作用,甚至不渲染默认边框。
立即学习“前端免费学习笔记(深入)”;
有效子元素包括:input、select、textarea、button、radio/checkbox 组。
避免这样写:<fieldset><legend>说明</legend><p>请填写真实信息</p></fieldset> —— 纯说明建议改用 <div> + CSS。
fieldset[disabled] 的禁用逻辑与边界
给 fieldset 加 disabled 属性,不是加灰样式,而是递归禁用所有**直接子级**可交互控件(input、select、textarea、button),并自动排除在 FormData 提交之外。
关键细节:
- 被禁用的
input即使有name,也不会出现在form.submit()或new FormData(form)中 - 禁用效果**不穿透嵌套层级**:如果
input套在<div>里,它不受影响 -
legend本身不可交互,加disabled没效果 - IE11 对
button兼容性差,建议保底加style="pointer-events: none;"
别用 style="pointer-events: none" 或 opacity: 0.5 模拟禁用——它不阻止键盘操作,也不影响提交逻辑。
CSS 重置后必须手动补视觉分组线索
删掉 fieldset 默认边框和内边距后,用户完全看不出哪块是一组。视觉分组提示必须由你主动补上,否则键盘导航时焦点框无处附着。
实操建议:
- 清掉
border后,至少保留outline: 2px solid #999或box-shadow: inset 0 0 0 1px #ccc -
legend默认有margin-bottom,全清掉会让标题紧贴控件顶部;建议只设legend { margin: 0.5em auto 0.75em; } - 在
display: flex容器中放fieldset,legend容易偏移或被裁剪;不要对legend设display: flex,改用display: inline-flex+align-items: center - UI 框架(如 Bootstrap、Ant Design)可能悄悄剥离
fieldset和legend;务必打开开发者工具,确认它们真实存在于最终渲染的 HTML 中


















