maxlength 按 UTF-16 码元计数,常用汉字占 1 码元,但扩展区汉字、复合 emoji、零宽字符等会占多个码元;textarea 与 input 行为一致,但需注意输入法未上屏状态及 Safari 兼容性;若需按人眼字符(grapheme cluster)限制,须结合 Intl.Segmenter 或正则增强校验,并后端二次验证。

maxlength 对中文字符的计算基本准确,但不是“按字或按字节”,而是按 JavaScript 字符串的 .length 值——即 UTF-16 码元(code unit)个数。绝大多数常用汉字(如“你好世界”)都落在 Unicode 基本多文种平面(BMP),每个占 1 个码元,所以 maxlength="10" 就能输入 10 个汉字。
为什么有时中文输入“看起来不准”
真正出问题的不是中文本身,而是那些超出 BMP 的字符:
- 部分生僻汉字(如 U+20000 起的扩展 B 区汉字)会用两个码元表示 →
"?".length === 2 - 复合 emoji(如
"??"、带肤色修饰符的"??")由多个码元组成,可能占 2–4 个码元 - 用户从 Word 或网页复制带零宽空格(
"\u200b")、组合符号(如带声调的拼音"nǐ")的内容,也会额外增加码元计数
maxlength 在 <input type="text"> 和 <textarea> 中对中文表现一致吗
行为完全一致:都按相同规则计数,也都拦截键盘输入和基础粘贴。但要注意这些实际差异:
- 移动端中文输入法的“未上屏拼音”不计入长度,只有确认上屏后才触发截断
- Safari(尤其 iOS 旧版本)对
<textarea>的maxlength支持不稳定,建议加input事件兜底 -
<textarea>中的换行符"\n"算 1 个码元,和中文、英文一样
需要真正按“人眼看到的字数”限制?别只靠 maxlength
如果你的业务要求是“最多 10 个图形字符(grapheme cluster)”,比如一个 "??" 只算 1 个,那原生 maxlength 必然不够用:
立即学习“前端免费学习笔记(深入)”;
- 现代浏览器可用
Intl.Segmenter拆分图形字符,但兼容性需查(Safari 15.4+ 支持) - 降级方案可用正则
/\p{Extended_Pictographic}|\p{Emoji_Presentation}/u+ 手动遍历,但无法覆盖所有组合场景 - 更现实的做法是:保留
maxlength提供基础拦截,再用 JS 在input事件里做增强校验,并把超长提示写进aria-live区域
真正容易被忽略的是:你永远不知道用户会粘贴什么——一段从微信公众号复制的带样式文本、一个含零宽连接符的 emoji 序列、甚至一段 base64 编码的字符串,它们的码元数和视觉长度常常错位。前端限制只是第一道门,后端必须用等价逻辑(如 TextEncoder.encode(str).length 校验字节数,或用 ICU 库解析 grapheme)再过一遍。



















