必须配 且为 的首个子元素,否则可访问性、禁用行为和浏览器解析均失效; 是语义核心,缺失或错位会导致屏幕阅读器无法识别分组、边框不渲染、css 失效及 disabled 不传递。

必须配 <legend></legend>,且它得是 <fieldset></fieldset> 的第一个子元素;否则分组在可访问性、禁用行为和浏览器解析上都会失效。
为什么 <legend></legend> 不能省略也不能放错位置
<legend></legend> 不是装饰文字,而是 <fieldset></fieldset> 的语义核心。没有它,屏幕阅读器读不出“这是哪一组”,Chrome 和 Firefox 可能不渲染边框,CSS 选择器 fieldset 也可能不生效,disabled 属性更无法向下传递。
- 正确写法:
<fieldset> <legend>收货地址</legend> <input name="city"> </fieldset> - 错误写法:
<fieldset> <input name="city"><legend>收货地址</legend> </fieldset>(<legend></legend>不是首子元素) - 错误写法:
<fieldset> <legend></legend> <input name="city"> </fieldset>(空<legend></legend>被播报为“空白分组”) - 视觉隐藏时,用
position: absolute; clip: rect(1px, 1px, 1px, 1px);,别用display: none或visibility: hidden
disabled 属性到底禁用哪些控件
<fieldset disabled></fieldset> 确实能一键禁用整组,但只对它的**直接子级表单控件**生效:包括 <input>、<select></select>、<textarea></textarea>、<button></button> 和 <input type="radio"> 组。
- 如果控件被包在
<div> 里再放进 <code><fieldset></fieldset>,那disabled就传不到它身上 - 被禁用的控件不会出现在
FormData或form.serialize()结果中 -
<label></label>点击行为在 Chrome 和 Firefox 中不一致:Chrome 允许穿透点击禁用控件,Firefox 直接拦截,务必真机测试 - 别用
style="pointer-events: none"模拟禁用——它挡不住键盘输入,也不影响提交 - 每层都必须有非空、纯文本的
<legend></legend>,不能含<h3></h3>或<button></button> -
<legend></legend>内不要放任何可交互元素(比如按钮、复选框),否则会干扰焦点顺序 - 外层
disabled会穿透所有嵌套层级,但内层单独加disabled会覆盖外层状态,需谨慎协调 - UI 框架(如 Ant Design、Bootstrap)常剥离你写的
<fieldset></fieldset>和<legend></legend>,上线前务必检查渲染后的 DOM 是否真实存在 - 避免把几十个控件塞进一个
<fieldset></fieldset>,尤其跨功能模块(如“头像上传”和“密码重置”硬凑一组) - 每组至少包含一个可聚焦控件;只包
<p></p>或<div> 的 <code><fieldset></fieldset>会被浏览器忽略语义,甚至不渲染边框 - 收起/展开逻辑别用
display: none,改用inert+aria-expanded+max-height过渡,否则会切断可访问性和disabled继承 - Tab 导航测试比依赖浏览器默认行为更可靠:打开控制台,用
+console.log打印document.activeElement,实时观察焦点路径
嵌套 <fieldset></fieldset> 时最容易踩的坑
嵌套本身合法,但 ≥3 层就容易让键盘用户卡在焦点流里出不来,尤其当某层 <legend></legend> 缺失、为空或被错误隐藏时。
多组 <fieldset></fieldset> 怎么切才合理
不是按 HTML 结构切,而是按用户填写意图切——比如“登录信息”“隐私偏好”“收货地址”各自独立成组,每组一个明确主题。











