HTML 表单验证是前端开发里最常见、也最容易被忽略的基础能力。很多登录、注册、留言、搜索和订单页面,明明只需要浏览器原生能力就能拦住一批明显错误,却被直接丢给后端处理,结果用户体验变差,接口也承受了不必要的请求。
这篇教程从 required、pattern 到自定义错误提示,讲清楚 HTML 原生表单验证的常用写法、适用场景和注意事项。重点不是堆属性,而是让你知道什么时候该用原生验证,什么时候必须配合 JavaScript 与后端校验。
基础结构
一个可验证的 HTML 表单,通常由 <form>、输入控件、label、提交按钮组成。浏览器会在提交表单时自动检查必填、格式、长度、数字范围等约束,只要控件写了对应属性,就不需要额外引入插件。
<form action="/submit" method="post">
<label for="email">邮箱</label>
<input id="email" name="email" type="email" required>
<button type="submit">提交</button>
</form>
这里的 type="email" 会让浏览器检查邮箱格式,required 会要求用户必须填写。用户直接点击提交按钮时,如果字段为空或格式不对,浏览器会阻止提交并显示提示。
required 必填验证
required 是最常用的表单验证属性,用来声明某个字段不能为空。它可以用于文本框、邮箱框、密码框、单选框、复选框、下拉选择等控件。
<input type="text" name="username" required>
<input type="password" name="password" required>
<select name="city" required>
<option value="">请选择城市</option>
<option value="shenzhen">深圳</option>
</select>
下拉框使用 required 时,要特别注意默认选项的 value 应该为空。如果默认项也有实际值,浏览器会认为用户已经选择了内容,必填验证就失去了意义。

常见输入类型
除了 required,合理选择输入类型也很重要。HTML5 提供了很多语义化输入类型,浏览器会根据类型提供基础校验和更适合的输入体验。
<input type="email" name="email" required>
<input type="url" name="website">
<input type="number" name="age" min="1" max="120">
<input type="tel" name="phone">
<input type="date" name="birthday">
type="email" 适合邮箱地址,type="url" 适合网址,type="number" 可以配合 min 和 max 限制数值范围。移动端浏览器还会根据类型弹出不同键盘,比如邮箱键盘会更方便输入 @ 符号。
pattern 正则验证
pattern 用于给输入内容设置正则表达式规则,适合处理用户名、手机号、验证码、邮政编码等格式相对固定的字段。
<label for="username">用户名</label>
<input
id="username"
name="username"
required
pattern="[A-Za-z0-9_]{4,16}"
title="用户名只能包含字母、数字和下划线,长度为 4 到 16 位">
上面的规则表示用户名只能由字母、数字和下划线组成,长度为 4 到 16 位。需要注意的是,pattern 默认匹配整个输入值,不需要额外写 ^ 和 $ 也能完成完整匹配。
为了让用户知道为什么填写失败,建议同时写上 title。部分浏览器会把 title 内容作为提示的一部分,但不同浏览器展示方式并不完全一致,所以更稳定的提示通常还要配合 JavaScript。
长度与范围限制
文本长度可以使用 minlength 和 maxlength,数字范围可以使用 min、max 和 step。这些属性比把所有规则塞进一个正则里更清晰,也更容易维护。
<input type="text" name="nickname" minlength="2" maxlength="20" required>
<input type="number" name="quantity" min="1" max="99" step="1" required>
如果字段规则可以用原生属性表达,优先使用原生属性。比如昵称长度限制,用 minlength 和 maxlength 比写复杂正则更直观;商品数量限制,用 min 和 max 也比手写脚本更稳。
自定义错误提示
浏览器默认错误提示比较通用,有时不够贴近业务。想自定义提示,可以使用 JavaScript 的 setCustomValidity() 方法。当传入非空字符串时,字段会被视为验证失败;当传入空字符串时,表示清除自定义错误。
const passwordInput = document.querySelector('#password');
const confirmInput = document.querySelector('#confirmPassword');
function validateConfirm() {
const same = confirmInput.value === passwordInput.value;
confirmInput.setCustomValidity(same ? '' : '两次输入的密码不一致');
}
passwordInput.addEventListener('input', validateConfirm);
confirmInput.addEventListener('input', validateConfirm);
这个例子适合注册表单里的确认密码场景。浏览器原生属性可以检查必填和最小长度,而“两次密码是否一致”属于跨字段验证,需要通过 JavaScript 补充。
提交前检查
如果想在提交前主动判断表单是否合法,可以使用 checkValidity()。如果希望浏览器显示验证提示,可以使用 reportValidity()。
const form = document.querySelector('#registerForm');
form.addEventListener('submit', function (event) {
if (!form.checkValidity()) {
event.preventDefault();
form.reportValidity();
return;
}
// 表单通过前端验证后,再继续提交或发送 Ajax 请求
});
checkValidity() 只返回布尔值,不一定主动显示提示;reportValidity() 会触发浏览器提示。做 Ajax 表单时,这两个方法很常用,可以在发送请求前先挡掉明显错误。
禁用原生验证
有些项目会完全接管表单验证,比如使用自定义 UI 组件库或复杂的多步骤表单。这时可以在 form 上加 novalidate,禁用浏览器默认验证。
<form novalidate>
<input type="email" name="email" required>
<button type="submit">提交</button>
</form>
不过不建议为了“统一样式”就随手关闭原生验证。更稳妥的做法是保留原生约束能力,同时用 CSS 和 JavaScript 优化提示体验。只有当项目确实需要完整自定义交互时,再考虑使用 novalidate。
样式反馈
HTML 表单验证还可以配合 CSS 伪类给用户反馈。常用伪类包括 :valid、:invalid、:required 和 :optional。
input:invalid {
border-color: #e53935;
}
input:valid {
border-color: #43a047;
}
input:required + .hint::after {
content: ' *';
color: #e53935;
}
实际项目里要谨慎使用 :invalid。页面刚打开时,空的必填项可能已经处于 invalid 状态,如果直接标红,会给用户造成压力。更好的体验是用户输入过或提交过之后,再显示明显错误状态。
必须后端校验
前端验证只能提升体验,不能替代后端安全校验。任何用户都可以通过浏览器开发者工具删除 required、修改 pattern,甚至直接绕过页面向接口发请求。
因此,登录注册、订单提交、文件上传、金额数量、权限相关字段,都必须在后端再次校验。前端负责让普通用户少犯错,后端负责保证数据可信和业务安全。
实践建议
写表单验证时,可以按这个顺序处理:能用输入类型解决的,先选正确的 type;能用原生属性表达的,就用 required、minlength、maxlength、min、max;格式固定的字段再考虑 pattern;跨字段或业务规则再交给 JavaScript;最后所有规则都要在后端重新验证。
这样写出来的表单既轻量,又容易维护。对普通页面来说,HTML 原生验证已经能覆盖大量基础需求;对复杂业务来说,它也可以作为第一层体验优化,减少无效提交,让用户更快完成操作。













暂无评论内容