label必须通过for属性与input的id严格配对才能实现点击聚焦和屏幕阅读器识别,漏写for或id、大小写/符号不一致、id重复或用name替代id均会导致关联失效;嵌套写法虽免id但不适用于radio组或多控件场景。

label没绑定id就别指望屏幕阅读器能读出字段含义
用户点文字却没法聚焦输入框,不是样式问题,是
常见错误:<label>邮箱</label><input id="email">(漏for);或<label for="email">邮箱</label><input>(漏id);又或者用aria-label覆盖掉视觉标签,导致明眼人看到“手机号”,屏幕阅读器却念“编辑框”。
- 正确写法必须成对:
<label for="email">邮箱地址</label><input type="email" id="email" name="user_email"> - 嵌套写法合法但有风险:
<label>手机号<input type="tel"></label>,注意避免多层嵌套打乱焦点顺序 -
name不能省,且要语义化——name="user_email"比name="input-2"更能被后端和自动化测试识别
required动态开关时,removeAttribute比赋值false更可靠
JavaScript设el.required = true没问题,但设el.required = false根本不会移除属性,浏览器依然按必填校验。因为required是布尔属性,DOM中存在即生效,真假值赋值不触发属性增删。
典型翻车场景:选中“其他”才显示文本框并设required,但取消选择后只隐藏元素、没清理required → 提交被静默拦截,无提示,表单卡死。
立即学习“前端免费学习笔记(深入)”;
- 启用必填:
el.setAttribute('required', '')或el.required = true - 禁用必填:
el.removeAttribute('required')——这是唯一可靠方式 - 提交前主动验证:
if (!el.checkValidity()) { el.focus(); },别依赖浏览器自动弹窗
回车键在单文本框表单里会自动submit,不是bug是规范
只要表单内只有一个可编辑控件(type="text"、type="email"、<textarea>),回车就会触发表单提交。哪怕其他<input>是type="hidden"或display: none,只要没disabled,多数浏览器仍视为“非唯一”,但实践中仍按单控件逻辑处理。
后果是页面刷新、AJAX中断、状态丢失——而且不报错,你只会发现“点了回车,怎么跳走了?”
- 最稳解法:
form.addEventListener('submit', e => e.preventDefault()),再由JS接管后续逻辑 - 别试图靠加冗余
<input type="hidden">来绕过,这会让表单结构变脏,且移动端可能失效 - 如果真要用原生提交,确保表单至少有两个可见可编辑字段,或显式声明
<button type="button">替代默认submit
模态框里忘了管理焦点,等于给键盘用户挖坑
打开<dialog>或自定义弹窗后,焦点没落到第一个可聚焦元素,或Tab键直接跳到背景页,就是典型的键盘陷阱。iOS VoiceOver、NVDA等工具对此极其敏感,且无错误提示,用户只会“失联”。
关键不是“能不能聚焦”,而是“焦点是否可控循环”:Shift+Tab不该逃逸,Esc必须能关闭,关闭后焦点得回到触发按钮。
- 打开前记录触发源:
const trigger = document.activeElement; dialog.showModal(); - 打开后立即聚焦:
dialog.querySelector('button, input, select')?.focus()(确保目标元素没display: none或tabindex="-1") - 限制Tab循环:监听
keydown,捕获Tab键,用event.preventDefault()+ 手动.focus()跳转首尾元素 - 必须加
role="dialog"和aria-modal="true",否则辅助技术不认为它是模态上下文



















