HTML input 类型选择:语义、原生校验与安全边界
本文目录
<input> 的 type 不只是外观开关:它会影响控件语义、软键盘、可用属性、浏览器校验和辅助技术角色。优先选择准确类型,让浏览器提供合适的输入体验;但客户端约束只帮助正常用户更早发现错误,不能成为服务端信任边界。
按业务数据选类型
text/search:普通文本与搜索词。搜索提交仍应有可见按钮或 Enter 语义。email/url/tel:输入相应格式的字符串;浏览器会提供合适键盘或有限格式检查,但不验证邮箱归属、网址可访问或电话号码真实。number:可以参与数值运算的数值,结合min、max、step。金额、邮编、证件号、订单号即使含数字也通常是标识符,不应错误地使用数值控件。range:在上下界间选择近似值;精确值要同步显示并允许其他输入方式。date/time/datetime-local/month/week:日期时间组件由浏览器和系统本地化展示;提交值按标准化格式处理,不要假设用户看到的日期文本就是接口格式。checkbox/radio:布尔或互斥选项。相关选项用fieldset/legend组合并提供清晰标签。file:选择本地文件。accept是文件选择器提示,不是服务端验证。password:密码输入配合正确的autocomplete,如current-password或new-password;不要关闭密码管理器。
邮编若只接受六位数字,可使用 type="text" inputmode="numeric" pattern="[0-9]{6}"。这保留前导零,也不会让数值加减按钮出现在本应是标识符的字段上。正则规则要写清楚,并给出可读错误说明。
标签、帮助和自动填充
每个控件都应有持久可见的 <label>,用 for 与唯一 id 关联;placeholder 只能给示例或格式提示,不能代替标签,因为输入后它会消失,也不一定能被辅助技术当作名称。复杂规则使用 aria-describedby 关联说明和错误信息;错误不能只靠颜色表达。
按用途设置 name 和 autocomplete,例如邮件、姓名、地址、当前密码和新密码。相关单选项应共用 name;复选框要明确 unchecked 如何提交。禁用控件不会正常参与提交,readonly 与 disabled 的行为不同,不能为了视觉灰化而随意替换。
<form id="signup" action="/signup" method="post">
<label for="email">电子邮箱</label>
<input id="email" name="email" type="email" autocomplete="email" required
aria-describedby="email-help">
<p id="email-help">用于发送账户验证邮件。</p>
<label for="postal">邮政编码</label>
<input id="postal" name="postal" type="text" inputmode="numeric"
pattern="[0-9]{6}" autocomplete="postal-code" required>
<button type="submit">创建账户</button>
</form>
原生校验不是安全校验
required、min/max、step、minlength/maxlength、pattern 和特定类型可触发 Constraint Validation。type="number" 默认 step 是 1;允许小数必须明确规则,例如配置合适的 step。pattern 匹配整个值,业务允许的空白、国家区号和 Unicode 文本要先定义,避免把过严正则变成注册障碍。
浏览器可被开发者工具、脚本或直接 HTTP 请求绕过,服务端必须重新验证类型、长度、范围、权限和业务约束,并做输出编码。邮箱格式正确不代表邮箱可控制;登录/注册仍需邮件验证、限流、密码哈希和防滥用措施。文件上传还要服务端检查大小、扩展名、真实内容、恶意负载、存储权限和下载响应头,不能信任 filename、MIME 或 accept。
用原生校验时需测试焦点是否落到首个错误项、错误是否可读、动态清除后状态是否更新、键盘和屏幕阅读器是否可完成。自定义提示应与控件建立关联并在修正后清除;不要拦截浏览器的全部反馈后只留下没有定位的 toast。
参考:MDN input、Constraint Validation、label、fieldset、autocomplete、OWASP Input Validation。
Live Notes
留言提交后会先进入审核,审核通过后对其他读者公开。