required原生提示在Chrome/Firefox/Safari中位置文案不一致且不可定制;失效场景包括隐藏域、非表单内元素、select无空选项等;需移除required改用setCustomValidity并显式清空错误状态。
浏览器对 required 的原生提示完全自主控制:Chrome 显示气泡在输入框右下,文案是“请填写此字段”;Firefox 在左上角弹 tooltip,文案为“该字段是必填的”;Safari(尤其是 iOS)可能延迟显示、甚至不弹——不是 bug,是规范允许的差异化实现。你无法用 CSS 或 HTML 修改这些文案、位置、动画或延迟,required 本身不提供任何定制入口。
不是所有带 required 的 input 都能被验证:
input[type="hidden"]、input[type="button"]、contenteditable="true" 元素加 required 完全无效——它们没有“空值”语义,浏览器直接忽略select 必须有一个 <option value="">请选择</option> 作为初始项,否则默认选中第一项,required 失效<form> 标签内,或表单未通过 submit 事件提交(比如用 button + click 手动发请求),required 不会触发input[type="number"] 输入字母时,.value 是空字符串 "" 而非 "NaN",仍会被 required 拦截;但若输入 " "(空格),.value.trim() 后为空,同样拦截Firefox 默认给 :invalid 的 required 输入框加粉红色 box-shadow,而 iOS Safari 点击软键盘「完成」后不自动触发 blur 或 submit,导致提示压根不出现。
解决方式很具体:
立即学习“前端免费学习笔记(深入)”;
input:required:invalid, textarea:required:invalid { box-shadow: none; }
input + change,并在 blur 前调用 reportValidity() 强制提示required 单独工作——它只判空,不校验格式、长度、逻辑,且移动端行为碎片化严重只要还留着 required 属性,就和 setCustomValidity() 存在逻辑冲突:浏览器可能先走原生校验路径,跳过你的 JS 设置。正确做法是移除 required,完全由 JS 控制。
关键动作只有三个:
blur 或 input 时检查值,调用 input.setCustomValidity("错误文案") 或 input.setCustomValidity("")(清空必须显式调!)submit 事件中,用 form.checkValidity() 判断,失败时 e.preventDefault() + form.reportValidity()
input 和 change,在 blur 前补 reportValidity(),否则 iOS 用户点「完成」就卡住最易被忽略的一点:清空错误状态不是“默认恢复”,而是必须主动写 setCustomValidity("");漏掉这句,哪怕用户已输入内容,后续提交仍会弹旧错误。