阅读提要
表单是用户和系统之间最容易出摩擦的地方。这份清单覆盖标签、错误提示、提交态、输入类型和键盘操作五块,每一条都对应一个真实的体验损失。
为什么单独讲表单
其他页面做得再好,用户也可能只碰一个表单:注册、登录、下单、留言。
表单出问题的方式又特别隐蔽——不报错,不崩溃,只是让用户多花三十秒、多试两次、最后放弃。这类损失不会出现在监控里,只会出现在转化率上。
下面五块,按影响从大到小排。

一、标签不能靠占位符
最常见的错误:
<input placeholder="请输入邮箱">
占位符有两个致命问题:一输入就消失(用户忘了这栏填什么),对比度通常很低(浅灰色,视力差的人看不清)。
正确做法是显式的 <label>:
<label for="email">邮箱</label>
<input id="email" type="email" autocomplete="email">
如果设计上确实不想要可见标签,至少用 aria-label 或视觉隐藏的 label,保证屏幕阅读器能读到。
for 和 id 的关联还有一个好处:点标签能聚焦输入框,触屏上好用得多。
二、错误提示要落在字段上
提交后弹一个 Toast「请检查输入」,是最差的做法——用户得自己找哪一项错了。
字段级提示:
<input
id="email"
aria-invalid="true"
aria-describedby="email-error"
>
<p id="email-error" role="alert">邮箱格式不正确,例如 name@example.com</p>
三个要点:
- 位置:紧贴字段下方,不要放到表单顶部;
- 文案:说清「哪里错了」和「怎么改」,不要只说「格式错误」;
- 可访问性:
aria-invalid+aria-describedby,让读屏软件能关联错误与字段。
还有一个细节:校验时机。输入过程中实时校验会让人抓狂(刚打第一个字符就报错)。常见做法是「失焦时校验,提交时全量校验,改错后立即清除错误」。
三、提交态必须可见
点击提交后,如果按钮没反应,用户会再点一次、两次、三次——于是产生三条重复数据。
async function submit() {
if (submitting.value) return
submitting.value = true
try {
await api.save(payload)
} finally {
submitting.value = false
}
}
按钮上要体现状态:disabled + 文案变成「提交中…」+ 一个旋转图标。三件事一起做,用户才知道「系统收到了」。
注意:disabled 会让按钮失去焦点,键盘用户会丢失位置。更好的做法是 aria-disabled="true" + 阻止重复提交,保留焦点。
四、输入类型决定手机键盘
这一条在移动端影响巨大:
<input type="email"> <!-- 键盘带 @ 和 . -->
<input type="tel"> <!-- 数字键盘 -->
<input type="number" inputmode="numeric"> <!-- 纯数字 -->
<input type="url"> <!-- 带 / 和 .com -->
验证码用 inputmode="numeric" + autocomplete="one-time-code",iOS 和 Android 都能自动填充短信验证码。
type="number" 有两个坑:允许输入 e 和 -;滚轮会误改数值。金额、数量这类字段,用 inputmode="numeric" + pattern="[0-9]*" 更稳。
五、键盘能走完全程
用户填一个表单,手不应该离开键盘。
Tab顺序要和视觉顺序一致(别用tabindex正数打乱);Enter在单行输入里应该提交(多行文本框除外);- 焦点要有明显的可见样式(不要
outline: none了事); - 提交失败后,焦点移到第一个出错的字段。
最后一条最容易被忽略:长表单里,用户在底部点提交,错误在第一项,屏幕上什么都看不到。
还有几条零散的
自动填充属性要写全。 autocomplete="email"、autocomplete="current-password"、autocomplete="new-password"。写对了,密码管理器才愿意帮忙。注册和登录的密码框要用不同的值,否则浏览器会拿旧密码填新密码框。
必填项要有视觉标识,但不要只用星号。 星号对读屏软件不友好,用 required 属性 + 文案说明「以下均为必填」。
长表单要能分段。 一屏塞 20 个字段,用户会产生放弃的念头。分成两三步,每步 5-8 项,完成率明显更高。
不要在输入时清空已填内容。 校验失败后重新渲染表单,把用户填的东西弄丢,是最让人恼火的 bug。
一个自查清单
上线前逐条过:
- 每个输入都有可见标签,且
for关联正确; - 错误信息在字段旁,说明怎么改;
- 提交按钮有加载态,且防重复提交;
- 移动端键盘类型正确;
Tab能走完全程,焦点样式可见;- 自动填充属性写全;
- 校验失败不丢用户输入。
七条做到,表单的体验就从「能用」变成「不难用」。这个差别在转化率上通常是两位数。
你认为这篇文章怎么样?
还没有表情反馈

一起聊聊
一个想法、一点补充,或一句简单的问候。
评论与回复
友善交流,彼此尊重第一句话,留给你。
读完有什么感受?欢迎成为第一个分享的人。