fieldset 和 legend 是唯一同时满足语义分组、可访问性命名、原生批量禁用的 HTML 原生机制;div 等替代方案无法完整支持键盘导航、屏幕阅读器播报和提交排除。
fieldset 和 legend 是唯一能同时满足语义分组、可访问性命名、原生批量禁用三件事的 HTML 原生机制;其他方案(比如用 div + aria-labelledby)只能模拟其中一两项,且在键盘导航、屏幕阅读器播报、提交排除等关键环节会失效。常见错误是把“收货地址”“账单地址”两组控件都塞进 <div class="section"> 里,再加个 <h3> 当标题。问题在于:
• 屏幕阅读器无法将该 <h3> 绑定为整组控件的可访问名称
• Tab 键不会自动跳过整组(哪怕你加了 tabindex="-1")
• 没法用 fieldset[disabled] 真实禁用所有子控件并排除提交
• 搜索引擎和辅助工具可能报错 “missing landmark” 或 “ambiguous grouping”
这是最常被破坏的语义链。
• 错误写法:<fieldset><div><legend>地址</legend></div><input name="city"></fieldset> → legend 被忽略,NVDA/VoiceOver 完全不播报组名
• 错误写法:<fieldset><input name="zip"><legend>地址</legend></fieldset> → Safari 旧版本可能跳过 legend
• 正确写法:<fieldset><legend>收货地址</legend><input name="city"></fieldset>
• legend 内容必须是纯文本,不能含 <span>、<strong> 或空格占位符(如 )
这个限制直接影响禁用逻辑是否可靠。
• 有效:<fieldset disabled><input name="phone"><select name="country"></fieldset> → 两个控件都被禁用、不提交、focus() 失败
• 无效:<fieldset disabled><div><input name="phone"></div></fieldset> → input 不受影响,仍可聚焦、提交
• IE11 对 <button> 在 fieldset[disabled] 下兼容性差,建议额外加 style="pointer-events: none;" 保底
• 禁用后,整组在 FormData 中自动被排除,无需手动过滤
注册页、多步骤表单、保险报价等场景,天然适合按用户心智模型拆分成多个平行 fieldset。
• 正确:<form><fieldset><legend>身份信息</legend></fieldset><fieldset><legend>联系方式</legend></fieldset></form>
• 错误:<fieldset><legend>主信息</legend><fieldset><legend>紧急联系人</legend></fieldset></fieldset> → 嵌套破坏语义层级,部分辅助技术无法识别内层 legend
• 删除默认边框和内边距后,必须手动补视觉线索(如背景色、分割线、间距),否则用户完全看不出哪块是一组
• 每个 fieldset 都应有明确、简短、动词导向的 legend(例如 “设置密码”,而非 “密码相关”)
立即学习“前端免费学习笔记(深入)”;
真正难的不是写出fieldset,而是让每个 legend 成为屏幕阅读器用户能直接跳转、能记住、能依赖的锚点——这要求它位置绝对正确、内容绝对干净、上下文绝对独立。