required校验仅在表单提交或调用checkvalidity()/reportvalidity()时触发,不实时响应输入;对hidden无效,checkbox/radio校验是否选中;需js配合动态控制、自定义提示及移动端兼容处理。

required 属性的验证何时真正触发
浏览器不会在页面加载时立即校验 required 字段,它只在用户尝试提交表单(submit 事件)或显式调用 checkValidity() 时才执行检查。即使字段为空,只要没触发提交或校验调用,就不会弹出提示、也不会添加 :invalid 伪类样式。
- 表单内任意
<input required>元素未填,点击<button type="submit"></button>会阻止提交,并聚焦到第一个必填空字段,同时显示浏览器默认提示(如 Chrome 的“请填写此字段”) - 手动调用
form.checkValidity()或input.reportValidity()会立即触发校验,返回false并显示提示(后者还会聚焦) -
required对type="hidden"无效;对type="checkbox"或type="radio",校验逻辑是“至少一个被选中”,而非“值非空”
如何避免 required 校验干扰用户操作流程
常见误区是把 required 当作“实时提醒开关”。它不响应输入过程,也不支持自定义错误文案。若需输入中提示或动态控制必填状态,必须配合 JavaScript。
- 动态切换必填:用
input.required = true/false修改属性,但注意 DOM 属性变更后需手动调用input.checkValidity()才能更新 UI 状态(例如移除:invalid) - 屏蔽默认提示:监听
invalid事件并调用event.preventDefault(),再自行渲染错误消息——但此时reportValidity()不再生效,需改用setCustomValidity() - 慎用
novalidate:加在<form novalidate></form>上会彻底禁用所有原生校验(包括required和type="email"),仅适合完全接管校验逻辑的场景
required 与 setCustomValidity 的协作陷阱
setCustomValidity() 会覆盖 required 的内置校验结果。一旦对某个元素调用了 setCustomValidity("xxx")(哪怕传空字符串),该元素就不再受 required 约束,除非你显式重置为 setCustomValidity("")。
- 错误写法:
input.setCustomValidity("不能为空"); input.reportValidity();→ 后续即使填了内容,仍报错,因为自定义错误未清空 - 正确模式:每次输入后都应根据业务逻辑重新设置,例如
input.addEventListener("input", () => { input.setCustomValidity(input.value.trim() ? "" : "此项必填"); }); - 注意兼容性:
setCustomValidity("")是重置的关键,不能省略;部分旧版 Safari 对空字符串处理不稳定,建议统一用""
移动端表单中 required 的特殊表现
在 iOS Safari 和部分安卓 WebView 中,required 字段的默认提示可能不显示,或仅在键盘收起后才触发,导致用户误以为已通过校验。
- 根本原因:某些 WebView 对
submit事件的捕获时机异常,或对input类型(如type="number")的空值判定不一致(例如输入框显示为空,但value实际为"0") - 稳妥做法:提交前用 JS 显式遍历必填字段,检查
element.value.trim() === "",而不是依赖checkValidity()的返回值 - 额外注意:
type="search"在 iOS 上会自动补全空格,value可能含不可见字符,建议统一用value.replace(/\s/g, "") === ""判空
required 是轻量级入口,但它的触发时机、重置逻辑和移动端行为都容易被忽略。真正在意用户体验时,往往得用 JS 补全校验链路,而不是只靠一个属性。











