label 与 for/id 必须严格配对,大小写、连字符、空格或 JS 动态改 ID 后未同步均会导致绑定失效;fieldset+legend 是表单分组唯一可靠语义方案;required 不触发实时反馈,需配合 aria-invalid 和 aria-errormessage 实现无障碍校验;type 和 autocomplete 必须按规范设置以启用浏览器原生能力。

label 和 for/id 必须严格配对,不能靠视觉对齐
表单控件没被读出来、点击 label 文字不聚焦 input——八成是 for 和 id 值不一致。大小写、连字符、空格、JS 动态改 ID 后没同步更新 for,都会断开绑定。
实操建议:
- 手写时统一用小写 + 下划线,比如
id="first_name"配for="first_name" - React 中别硬写字符串,用变量或
htmlFor={id}保证同步 - 在开发者工具的 Accessibility 面板里检查
label的 “Name” 是否可读、是否指向正确控件 - 避免
<label>姓名<input></label>这种包裹写法,旧浏览器和自动化测试可能识别失败
fieldset + legend 是分组唯一可靠方案
用 <div class="section"> 包一堆单选按钮,屏幕阅读器只会平铺读出所有选项,完全不知道它们属于“性别”还是“兴趣”。只有 <fieldset> + <legend> 才能被识别为逻辑组。
容易踩的坑:
立即学习“前端免费学习笔记(深入)”;
-
<legend>写成空标签、只放图标(如<svg>),导致无障碍名称缺失 - 嵌套多个
<fieldset>但漏闭合,后续控件可能被浏览器吞掉 - 用
role="group"+<div>模拟,语义强度远不如原生
如果不想显示 <legend> 文字,用 clip-path: inset(100%) 或绝对定位隐藏,但必须保留 DOM 结构。
required 不等于错误提示,aria-invalid 必须手动同步
required 只拦提交,不告诉用户“现在就错了”。输错邮箱格式、密码太短,required 完全不响应;JS 校验后只加红边框,屏幕阅读器照样读不出问题。
关键动作:
- JS 验证失败时,必须设
aria-invalid="true",成功时设回"false" - 错误文案要具体,比如 “邮箱缺少 @ 符号”,而不是 “格式错误”
- 用
aria-errormessage指向错误提示元素的id,确保辅助技术可关联 - 提交失败后,调用
input.focus()聚焦第一个aria-invalid="true"的字段
type 和 autocomplete 决定键盘、校验、自动填充能否生效
全用 type="text" 等于放弃浏览器能力:iOS 不弹数字键盘、Chrome 拒绝保存密码、邮箱格式无基础校验、自动填充失效。
按场景选:
- 邮箱:必须
type="email"+autocomplete="email" - 密码:用
type="password"+autocomplete="current-password"(新密码用"new-password") - 手机号:用
type="tel",iOS 自动弹数字键盘 - 地址字段:优先用标准
autocomplete值,如"street-address"、"country",别自定义
注意:autocomplete 值必须完全匹配规范,拼错一个字母,Chrome 就不触发保存。



















