HTML原生minlength/maxlength可基础控长,但仅适用于部分type且易被绕过;pattern正则校验更可靠;JS需用Intl.Segmenter等处理Unicode视觉长度;前后端必须统一按Unicode字符数校验并预留数据库余量。

用 minlength 和 maxlength 做基础长度控制
HTML 原生就支持字段长度范围校验,直接在 <input> 或 <textarea> 上加 minlength 和 maxlength 即可。浏览器会自动阻止提交,并在调用 checkValidity() 时返回 false。
注意:这两个属性只对 type="text"、"email"、"password"、"search"、"tel"、"url" 和 <textarea> 生效;对 type="number" 无效(它校验的是数值范围,不是字符串长度)。
-
minlength="3"要求用户至少输入 3 个 Unicode 字符(不是字节),中文、emoji 都算 1 个 -
maxlength="20"到达上限后,输入法上屏、粘贴、拖入文本都会被截断或拒绝 - 两者可共存:
<input type="text" minlength="3" maxlength="20">
为什么 input 的 pattern 有时比 minlength/maxlength 更可靠
原生属性校验在某些场景下会被绕过:比如用户禁用 JS 后仍可手动删掉 maxlength 属性再提交;或者表单用 formnovalidate 提交;甚至部分旧版 Safari 对 minlength 支持不一致。
用 pattern 可以把长度逻辑写进正则,强制绑定到整个字段验证链中:
立即学习“前端免费学习笔记(深入)”;
<input type="text" pattern=".{3,20}" title="请输入 3 到 20 个字符">
说明:
-
pattern中的.{3,20}表示任意字符(除换行符)恰好 3–20 个,和minlength/maxlength语义一致 - 必须配
title属性,否则出错时提示为空白(Chrome 等浏览器默认只显示title文本) - 注意:正则默认是“全匹配”,不需要加
^和$,HTML 自动包裹 - 若需支持换行,改用
[\s\S]{3,20},但<input>本身不接受换行,所以仅<textarea>有此需求
JS 手动校验时别只看 value.length
用户粘贴富文本、输入带零宽字符(如 \u200b)、或使用某些输入法时,value.length 可能和视觉长度严重不符。比如 emoji 组合(??)在 JS 中占 4 个码点,.length 返回 4,但用户只当它是 1 个字符。
更稳妥的做法是用 Intl.Segmenter(现代浏览器)或回退到正则统计“用户感知长度”:
function visualLength(str) {
if (Intl.Segmenter) {
return Array.from(new Intl.Segmenter('zh').segment(str)).length;
}
return str.replace(/[\uD800-\uDFFF]/g, '_').length;
}
实际使用时,建议只在关键字段(如用户名、昵称)做这层校验,普通字段仍用原生属性 + pattern 足够。
服务端永远要重新校验,且逻辑必须和前端一致
前端所有长度限制都可被绕过——删 DOM 属性、curl 提交、抓包重放。服务端若只按字节长度(如 UTF-8 byte length)校验,而前端按 Unicode 字符数校验,就会出现“前端说合法、后端拒收”的问题。
例如:用户输入 20 个中文,在前端 value.length === 20 合规;但若后端按 MySQL utf8mb4 字节算,每个中文最多占 4 字节,20 个就是 80 字节——如果数据库字段定义为 VARCHAR(50),就会截断或报错。
所以:
- 前后端约定统一按“Unicode 码点数量”(即 JS
str.length)校验,而非字节 - 数据库字段长度预留足够余量(如前端限制 20 字符,后端字段设为
VARCHAR(100)) - 后端校验失败时,错误信息应明确提示“长度需在 X 到 Y 个字符之间”,而不是“超出字段长度”
长度校验看着简单,真正麻烦的是 Unicode 处理、前后端对齐、以及用户输入方式的多样性——别让一个 maxlength 给你埋了线上 bug。



















