HTML5原生校验需配合required、type、pattern等属性及JS状态管理;现代浏览器稳定支持这些属性,但pattern须全匹配且需手动清空setCustomValidity错误。

required 属性必须加,但光靠它远远不够;type="email" 会触发浏览器内置邮箱校验,但不等于能拦住所有非法邮箱;pattern 是最灵活的校验入口,但正则写错会导致整个字段“永远报错”或“永远通过”。原生校验不是开关,而是一套需要配合状态管理、CSS 和 JS 补位的机制。
哪些 HTML5 属性真正在浏览器里起作用
现代浏览器(Chrome 120+、Firefox 115+、Safari 17+)对以下属性有稳定支持,且校验逻辑一致:
-
required:空值时阻止提交,并触发:invalid伪类 -
type="email":只校验基本格式(含 @ 和 .),不查域名是否存在 -
type="url":要求以http://或https://开头(部分 Safari 允许省略) -
minlength/maxlength:按 UTF-16 码点计数,中文、emoji 都算 1 个字符 -
min/max(仅type="number"或date):数值比较严格,"10"和10在 JS 中等价,但在原生校验中只认字符串解析后的值 -
pattern:正则必须全匹配(隐式加 ^ 和 $),且不支持g或m标志
注意:type="tel" 不做任何格式校验,只是唤起手机数字键盘;placeholder 和 title 不参与校验逻辑,仅作提示。
pattern 正则怎么写才不会失效
pattern 的常见坑是:写了正则却没效果,或者一输就报错。根本原因是浏览器在校验时自动包裹了 ^ 和 $,你写的正则必须能“从头到尾”匹配整个输入值。
- 错误写法:
pattern="[0-9]{11}"→ 只匹配 11 位纯数字,但用户可能输空格或横线 - 正确写法:
pattern="^1[3-9]\d{9}$"(大陆手机号)或pattern="^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$"(宽松邮箱) - 想允许空格/分隔符?用
[\s\-]显式包含,并确保整体仍能全匹配,例如:pattern="^1[3-9]\d{1}\s?\d{4}\s?\d{4}$" - 调试技巧:在控制台执行
/^1[3-9]\d{9}$/.test("13812345678"),结果为true才可放心放进pattern
submit 事件里调用 checkValidity() 为什么有时没用
表单的 checkValidity() 方法返回 false,不代表你能直接靠它拦截所有问题——它只反映当前各字段的原生约束是否满足,不包括自定义规则(如两次密码一致、用户名查重)或已被 setCustomValidity("") 清空的错误。
立即学习“前端免费学习笔记(深入)”;
- 典型误用:
form.addEventListener('submit', e => { if (!form.checkValidity()) e.preventDefault(); })→ 这只能拦住原生校验失败,但若你手动清除了错误又没重设,它就放行了 - 安全做法:始终在 submit 回调里重新校验关键业务逻辑,比如:
if (pwd.value !== pwdConfirm.value) { pwdConfirm.setCustomValidity('两次输入不一致'); } - 别依赖
form.reportValidity()自动弹提示:它只触发浏览器默认气泡,样式不可控,移动端常被系统键盘遮挡 - 兼容性提醒:IE 完全不支持 Constraint Validation API,哪怕加了
required也无校验行为
为什么 setCustomValidity 必须配 input 事件清空
setCustomValidity() 设置的错误是“粘性”的:一旦设为非空字符串,该字段就一直保持 validity.valid === false,直到你显式调用 setCustomValidity("")。
- 不清理的后果:用户改完错误后,
checkValidity()仍返回false,表单无法提交 - 推荐时机:在
input或blur事件中先清空,再根据新值判断是否需重设错误,例如:
const emailInput = document.querySelector('input[type="email"]');
emailInput.addEventListener('input', () => {
emailInput.setCustomValidity('');
if (emailInput.value && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailInput.value)) {
emailInput.setCustomValidity('邮箱格式不正确');
}
});
这个模式看似啰嗦,却是避免“错误残留”的唯一可靠方式。很多项目线上 bug 就出在这里:用户输错 → 报错 → 改对 → 还是报错 → 最后发现是忘了清空自定义错误。



















