fieldset的核心作用是为表单控件提供语义化逻辑分组,确保键盘导航、屏幕阅读器识别及表单API正确解析;legend必须为首个子元素且不可包裹标题标签或为空,否则导致可访问性失效。

fieldset 的核心作用不是“加个边框”,而是给表单控件打上可被浏览器、读屏软件和表单 API 识别的逻辑分组标签。没它,视觉再整齐,键盘 Tab 键一按就乱套,屏幕阅读器也读不出“这是收货地址组”还是“这是发票信息组”。
为什么 legend 必须是 fieldset 的第一个子元素
浏览器和读屏软件靠这个位置来提取分组名称。写在后面、用 position: absolute 移走、或包在 <h3> 里,都会导致名称获取失败——NVDA 可能静音,Chrome 可能跳过整个 fieldset。
- 正确:
<fieldset><legend>配送时间偏好</legend><input type="radio"></fieldset> - 错误:
<fieldset><input type="radio"><legend>配送时间偏好</legend></fieldset>(语义断裂) - 错误:
<legend><h3>配送时间偏好</h3></legend>(<h3>干扰可访问性树) - 空
<legend></legend>等同于没写,WCAG 检查直接报错
fieldset[disabled] 真实禁用的是什么
它只对 fieldset 的**直接子级**标准控件生效:<input>、<select>、<textarea>、<button>、<input type="radio"> 组。嵌套在 <div> 里的控件不会被禁用,也不会从 FormData 中排除。
- 生效:
<fieldset disabled><legend>发票信息</legend><input name="title"></fieldset> - 不生效:
<fieldset disabled><legend>发票信息</legend><div><input name="title"></div></fieldset> - 值不会提交:即使 JS 改了
input.value,只要它被fieldset[disabled]直接包裹,就不会进FormData - label 点击行为不一致:Chrome 允许穿透聚焦,Firefox 拦截,必须真机测试
嵌套 fieldset 的实际风险
语法合法,但 ≥3 层嵌套极易破坏键盘导航流。焦点可能卡在某一层出不来,尤其当内层 legend 缺失、被隐藏或含交互元素时。
立即学习“前端免费学习笔记(深入)”;
- 优先用单层
fieldset+ CSS(如margin、border-bottom)做视觉分隔 - 必须嵌套时,确保每层都有纯文本
<legend>,且不放<button>或contenteditable - UI 框架(如 Ant Design)常剥离
fieldset,只留 div —— 务必检查渲染后 DOM 是否真实存在 - 用
+console.log打印document.activeElement观察焦点路径,比依赖默认行为更可靠
最易被忽略的点是:哪怕所有样式都删光,fieldset + legend 的语义和行为依然完整;但一旦漏掉 legend 或放错位置,可访问性和表单逻辑就彻底断了,而且这种问题在线上环境才暴露得最明显。



















