label和for/id必须严格配对,禁止包裹式写法;input需唯一id且与for值完全一致;type与autocomplete须按场景配对;错误反馈须实时定位并同步aria-invalid与aria-describedby;fieldset+legend为逻辑分组唯一可靠方案。

label 和 for/id 必须配对,别信“看着像就行”
很多页面把 label 和 input 并排放,样式调得整齐,但没写 for 和 id,结果屏幕阅读器读不出字段含义,移动端点击区域也只响应 input 本身——用户点文字没反应。
-
input必须有唯一id,label的for值必须与之严格一致 - 禁止用包裹式写法
<label>姓名<input></label>:旧浏览器、自动化测试工具、部分读屏软件会忽略或误读 - 复选框/单选按钮的
label应包裹input本身(不是只包文字),才能实现整个标签区域可点击
type 和 autocomplete 要按场景配对,别全塞 type="text"
用 type="text" 扛所有输入,等于主动放弃浏览器原生能力:键盘弹错、校验缺失、自动填充失效,全是连锁反应。
- 邮箱字段必须用
type="email"+autocomplete="email",否则 iOS 键盘不显示@快捷键,Chrome 也不触发基础格式校验 - 密码字段要区分场景:
autocomplete="new-password"(注册)、autocomplete="current-password"(登录),否则浏览器可能拒绝保存或填错 - 手机号用
type="tel",iOS 自动弹数字键盘;地址类字段优先用标准值如autocomplete="street-address"、autocomplete="country" -
placeholder只是补充提示,不能替代label;它一输入就消失,对认知障碍用户极不友好
错误反馈必须实时、定位、可操作,别等提交才报错
等用户点“提交”才统一报错,等于把调试工作甩给用户。验证该发生在 blur 或 input 事件中,且错误信息要明确指出“哪个字段”“为什么错”“怎么改”。
- JS 校验后,必须同步设置
aria-invalid="true",并用aria-describedby关联具体错误文案 ID,让读屏器自动朗读 - 视觉反馈不能只改边框颜色:加图标、调整间距、确保文字对比度 ≥ 4.5:1
- 提交失败后,用
input.focus()聚焦第一个aria-invalid="true"的字段,别让用户手动滚动找 - 已填内容必须保留,哪怕提交失败,也别清空整个表单——这是信任底线
fieldset + legend 是逻辑分组的唯一可靠方案
用 CSS class 模拟分组(比如加个 <div class="section-title">联系方式</div>)对可访问性无效。屏幕阅读器无法识别“这下面几个字段是一组”,也无法快捷跳转。
立即学习“前端免费学习笔记(深入)”;
-
fieldset+legend是 HTML 原生分组语义,legend内容会被读作“联系方式组”,然后依次读出该组内每个带label的控件 - 多步骤表单中,可用
fieldset disabled一键禁用非当前步的所有控件,比遍历每个input更轻量、更可靠 - 配合 CSS 的
fieldset:disabled input选择器,能统一控制禁用态样式,移动端竖屏下legend还能天然支持折叠/展开交互
表单结构一旦定型,后续加 JS 验证或 UI 动效都难挽救语义缺陷——最容易被忽略的,其实是最初几行 HTML 的写法。



















