表单设计 是做什么的?
表单是一场对话,组织方提出请求,用户以时间、精力和风险作为代价。一个表单行之有效,当且仅当每个问题都物有所值,每个答案都能以用户自己的方式给出,并且每个错误都能及早发现、就地解释,而且能够在不丢失已填写内容的情况下修复。最常见的模型失败案例是那些看似完成实则不然的表单:占位符标签、随意添加的必填字段、对卡号使用 type="number"、缺少 autocomplete、仅以浏览器气泡或红色边框显示错误、提交按钮写着“提交”,以及仅测试过成功路径。
应用 interface-guidelines 的优先级原则(人人可用 > 诚实表达 > 言简意赅 > 答案优先 > 错误可修复 > 布局稳定 > 可能性可见 > 遵循惯例 > 打磨细节)。如果该技能已安装,请先阅读其 SKILL.md。它的 references/human-interface.md 第3节包含了表单规则基线(可见标签、可选标记、粘贴、验证时机、禁用提交、保存行为);本技能在此基础上更进一步,不再重复那些内容。
简析
在绘制任何字段之前,请先回答以下问题。如果表单有超过五个问题,请把答案写下来。
- 每个答案用于什么? 说出使用该答案的决策或操作。没有明确用途的字段将被删除。
- 谁在填写?多久一次?使用什么设备? 是用户一生可能只填一次的申请(使用手机),还是每天录入200条记录的职员(使用台式机)。这决定了是采用“一页一问”还是“一页全填”的设计。
- 这些数据是谁的? 是用户自己的数据(适用自动填充,适用 WCAG 1.3.5),还是他人的数据(如由工作人员录入的收款人、病人、客户)。
- 用户手头有答案吗? 如护照号、保单ID、去年收入。如果没有,请提前告知需要准备什么,并允许保存进度。
- 错误答案的代价是什么? 一旦提交什么不可撤销(支付、法律声明、公开发布)?
- 用户在哪里? 国家、文字系统、地址格式、电话格式、姓名结构。
- 系统已经知道什么? 绝不要询问系统已知的信息(WCAG 3.3.7)。
- Agent 读者: 是否有 AI 智能体会替用户填写此表单(自动填充扩展、浏览器 Agent、助手)?对于公开的表单,假设答案为“是”。
规则
少问
- 在设计字段之前就删除不必要的字段。 每个字段必须有明确的当前用途,而不是“可能有用”。Baymard 发现平均结账流程有11.3个字段,而8个就足够了;字段数量比步骤数更影响体验。[P: Baymard 2024]
- 使用一个字段收集完整姓名,除非姓名各部分用于特定功能(如排序、正式称呼)。许多姓名无法区分为“名”和“姓”。绝不要求提供姓氏。[S: W3C i18n; P: Baymard]
- 将很少使用的字段隐藏在链接后面,而不是做成必填输入:如地址第二行、公司名、优惠码。[P: Baymard]
- 默认将账单地址设为与送货地址相同,提供一个已勾选的复选框来隐藏账单地址字段。[P: Baymard]
- 在交易完成后提供创建账户的选项,不要将其作为交易前的障碍。[P: Baymard]
- 当“我不知道”是有效答案时,就允许它,而不是强迫用户猜测。[S: GOV.UK 问题页面]
- 能推导出的信息就推导出来: 从邮政编码推导城市和地区(如果可靠),从卡号推导卡类型,从地址查询推导国家。保持推导结果可见且可编辑。[P: Baymard]
结构与流程
- 根据简析选择表单形态,而不是凭习惯。 对于罕见、有压力或不熟悉的任务:一页一问,问题作为
h1/legend。对于频繁的专业录入:一页多字段,分组,支持键盘快速操作。GOV.UK 的每个服务都从一页一问开始,只有在研究证实后再合并。[S: GOV.UK 表单结构] - 按照用户思考的顺序排列问题,最容易和最确定的放在最前面,并通过分支逻辑确保每个人看不到不适用于自己的问题。[S: GOV.UK; J]
- 在用户开始前告知需要准备什么(文件、时间、费用),以及提交后会发生什么。[S: GOV.UK 开始页面]
- 需要多次会话的长表单使用任务列表,带有清晰的状态和保存并返回功能。仅在用户无法一次性完成或必须自行选择完成顺序时使用。[S: GOV.UK 任务列表]
- 确保返回功能正常。 在问题页面上包含“返回”链接,并确保浏览器的返回按钮正常;返回后应显示之前已填充的答案。[S: GOV.UK]
- 对重要流程,最终提供检查答案页面: 每个答案旁边都有一个“更改”链接,其可访问名称指明字段(如“更改出生日期”),编辑后返回摘要页面。[S: GOV.UK 检查答案; WCAG 3.3.4]
- 多列布局会破坏用户和 Agent 的阅读顺序。 使用单列,除非是自然成对的短字段(如到期月份和年份、城市和邮政编码)。[P: Baymard, Wroblewski; J]
标签、提示和分组
- 标签置于字段上方。 Penzo 2006 报告的速度优势来自一个小型非正式眼动测试,并被 Das 2008 否定;选择顶部标签是因为它们能适应窄屏、长翻译和缩放,而不是因为它们被证明最快。[E, weak: Penzo 2006, Das 2008]
- 提示内容放在标签和字段之间,并使用
aria-describedby关联。 格式示例(如“例如 27 3 2007”)属于提示,绝不要放在占位符中。[S: GOV.UK] - 使用
fieldset和legend对相关控件进行分组: 每组单选按钮、复选框以及多部分答案(日期、信用卡到期日)。legend就是问题本身。[S: WCAG 1.3.1; GOV.UK] - 在单问题页面上,label 或 legend 就是页面标题,以便屏幕阅读器只读一次。[S: GOV.UK 问题页面]
- 将可选字段标记为“(optional)”,不要使用星号表示必填。如果大多数字段都可选,请质疑它们是否应该存在。[S: GOV.UK]
输入类型与自动填充
- 在每个涉及用户个人信息的字段上设置
autocomplete,使用精确的 WHATWG 标记(如given-name、email、postal-code、cc-number、one-time-code、new-password)。这为浏览器自动填充、密码管理器和 Agent 填写提供支持,也是 WCAG 1.3.5 的要求。在个人数据字段上使用autocomplete="off"视为缺陷。[S: WHATWG autofill; WCAG 1.3.5] - 使用
type表示语义,使用inputmode控制键盘类型。 在适用处使用type="email"、type="tel"、type="url"。由数字组成的标识符(卡号、邮政编码、账号、验证码)应使用type="text" inputmode="numeric",绝不使用type="number",因为后者会丢弃前导零、滚动时变化、对长值进行四舍五入,并影响听写软件。[S: GOV.UK 2020; MDN] - 优先使用原生控件。 可用选项少于十几个时用
select;选项较少且需要用户比较时用单选按钮;国家等长列表使用带键入搜索的组合框(combobox)。自定义下拉框会对其选项对 Agent 隐藏。[S: APG; P: probe in interface-guidelines] - 可记忆的日期使用三个文本字段(日、月、年),出生日期使用
bday-*标记,并接受月份名称。日期选择器仅适用于用户相对于日历选择日期的场景。[S: GOV.UK 日期输入] - 字段宽度应与预期答案的长度匹配。 一个像街道名输入框一样宽的邮政编码输入框会提供错误暗示。[S: GOV.UK; J]
- 接受用户格式的答案: 卡号和电话号码中的空格和破折号,邮政编码中的大小写,月份名称,前导或尾随空格。在服务器端进行标准化处理。[S: GOV.UK]
- 针对特定字段的模式(按国家区分的姓名、地址、电话、货币、信用卡、文件)在
references/fields.md中。
验证与错误
- 默认在提交时验证;仅在用户离开一个已完成的字段后进行内联验证,并在修复后立即清除错误。 绝不要在用户敲击第一个字符时就标记错误。证据存在冲突:Bargas-Avila 2007 发现完成后列出错误列表优于即时错误;Wroblewski 2009 发现失焦时的内联验证有帮助(n=22)。GOV.UK 在提交时验证;Baymard 推荐在失焦时验证并在修正时移除错误。根据表单长度以及该字段本身是否可单独检查来决定。[E: Bargas-Avila 2007; E, weak: Wroblewski 2009; S: GOV.UK; P: Baymard]
- 提交失败时: 保留所有答案,在页面顶部放置一个错误摘要,其中每个问题都带有链接指向其对应字段,将焦点移至摘要,在页面标题前添加“Error:”,并在每个错误字段旁显示相同的错误文字。[S: GOV.UK 错误摘要; WCAG 3.3.1]
- 使用
aria-describedby将每条错误消息与其字段关联(如果愿意可以同时添加aria-errormessage;但其屏幕阅读器支持仍不均衡),并设置aria-invalid="true"。错误消息必须是可见文本:代理序列化器会忽略aria-invalid,但会保留相邻的文本。[S: WCAG 3.3.1; P: Roselli 2023; P: probe in interface-guidelines] - 关闭浏览器验证气泡(使用
novalidate)并在页面内渲染错误消息。气泡会消失,无法从摘要中链接,也不是页面文本。服务端验证仍然是权威的。[S: GOV.UK 验证] - 错误消息应说明如何修复,并且针对具体原因: 写“请输入一个过去的出生日期”,而不是“无效日期”。每种原因(为空、格式错误、超出范围)使用一条消息,并且使用表单自身的措辞。[S: GOV.UK 错误消息; WCAG 3.3.3]
- 用户无法通过编辑来解决的情况(如不符合条件、账户锁定、服务不可用)应显示为一个包含原因和后续步骤的页面,而不是字段错误。[S: GOV.UK]
登录、密码、通行密钥
- 允许密码管理器和粘贴功能正常工作。 使用
autocomplete="username"和current-password或new-password;绝不阻止粘贴;maxlength不要低于64;提供“显示密码”按钮;当提供了“显示密码”后,可以去掉确认密码字段。[S: NIST SP 800-63B-4 3.1.1.2; GOV.UK 密码输入; WCAG 3.3.8] - 没有组成规则,没有定期过期,没有提示。 而是将新密码与已知泄露密码列表进行比对,并说明为何某个密码被拒绝。[S: NIST SP 800-63B-4]
- 提供通行密钥选项,但不要在开始时强制用户选择: 保留用户名字段,添加
autocomplete="username webauthn"和条件 WebAuthn 请求,然后在密码登录后提供通行密钥创建选项。[S: WHATWG autofill; P: web.dev passkey autofill] - 一次性验证码: 一个字段,使用
autocomplete="one-time-code",inputmode="numeric",接受粘贴。使用拒绝粘贴的分离的单个数字输入框会违反 WCAG 3.3.8。[S: WCAG 3.3.8] - 不要说用户名或密码中是哪个错了。 [S: GOV.UK 密码]
- 不要使用拼图式 CAPTCHA 作为登录验证。 文本和逻辑拼图如果没有非认知替代方案,则违反 WCAG 3.3.8。[S: WCAG 3.3.8]
提交
- 提交按钮应注明其操作结果: “创建账户”、“支付 £42.00”、“发送申请”。步骤之间使用“继续”;仅当内容被保存时使用“保存并继续”。[S: GOV.UK 按钮; foundation]
- 法律、财务和数据删除相关的提交应可逆、可检查或需确认,并包含一个审核步骤(WCAG 3.3.4)。审核页面应精确展示将要发送的内容及其成本。[S: WCAG 3.3.4]
- 提交是幂等的: 提交进行中时禁用再次点击,在按钮上显示进度,并在服务器端使用幂等键保护。超时后的重试不得重复收费。[S: GOV.UK 按钮; P: Stripe 幂等性]
- 确认页面说明发生了什么、提供一个参考编号以及下一步做什么,并且页面在刷新后应仍然存在。消息提示不是收据。[S: GOV.UK 确认页面; foundation]
针对 Agent 读者
- 每个控件都有一个与可见标签匹配的程序化名称,且其选项是可枚举的(原生
select、可见单选按钮)。[J] - 约束条件(格式、长度、允许值)在提交前是可见文本,而不仅仅存在于
pattern属性中。[J] - 错误是字段旁和摘要中的文本,在修复前保持稳定。[J]
- 每一步的 URL 或标题应告知 Agent 其在整个流程中的位置;应存在“返回”和“更改”路径。[J]
- 由外部系统写入的文本(如从邮件预填的内容、引用备注)应显示为引用的数据,绝不作为标签或指令。[J]
- 重要的提交将权威保留在服务器端:检查答案页面帮助人类用户,但它不能阻止一个点击通过的 Agent。[J]
构建顺序
- 列出问题并为每个答案注明用途;删除没有用途的问题。
- 选择表单形态:单页、一页一问或任务列表。草拟分支逻辑。
- 编写文案:问题、提示、针对每种原因的每条错误消息、按钮标签、确认信息。
- 使用原生元素构建:
label for、fieldset/legend、正确的type、inputmode、autocomplete、novalidate。 - 服务端验证和幂等提交,然后使用相同消息的客户端验证。
- 错误状态:摘要、焦点、标题前缀、内联消息、保留已输入内容。
- 检查答案页面和确认页面;如果是多会话则包含保存并返回。
- 最后进行样式设计;品牌拥有视觉效果控制权(
brand-identity)。
验证
node <form-design>/scripts/form-check.mjs <url|file|dist> --try-submit对本地或测试构建执行。它会检查名称与可见标签的匹配、自动填充的有效性和用途、输入类型、粘贴、隐藏的原生单选按钮、组图例、错误连接、提交失败后的焦点以及提交用语。错误退出码为1。--try-submit会真实提交:切勿针对生产环境。node <interface-guidelines>/scripts/audit.mjs <url|dist>用于通用渲染审核(对比度、点击目标、键盘、重排、Agent稳定性)。- 使用密码管理器和浏览器自动填充进行填充:每个个人字段都能填充,且不会填入错误的输入框。
- 仅使用键盘填充,并在320像素宽度下使用200%文本大小进行测试。
- 仅凭可访问性快照作为 Agent 填充:按名称查找每个字段,读取所有选项,提交错误数据,读取错误信息,修复它们,完成提交。
- 坏数据测试: 一个单词的姓名、60个字符含撇号和重音的姓名、日本地址和爱尔兰无邮政编码地址、带空格的粘贴卡号、双击提交、流程中超时。
陷阱
- 将占位符用作标签,或使用会缩小到边框内并与边框对比度不足的浮动标签。
- 对卡号、电话号码、邮政编码或验证码使用
type="number"。 - 对个人信息字段使用
autocomplete="off"。 - 显示密码字段中禁止粘贴。
maxlength设置得过低(64以下)。- 自定义选择控件隐藏选项。
- 使用拼图 CAPTCHA。
- 拆分一次性验证码的输入框。
- 在提交前就要求创建账户。
- 对确认消息使用消息提示而非页面内容。
- 仅测试成功路径。
参考文献
- Baymard 2024 结账表单优化 — 字段计数和布局的基准数据。
- GOV.UK 表单设计模式 — 一页一问、错误摘要、检查答案、日期输入、密码输入。
- WCAG 2.2 — 1.3.1(信息和关系)、1.3.5(输入用途)、3.3.1(错误识别)、3.3.2(标签或说明)、3.3.3(错误建议)、3.3.4(错误预防(法律、财务、数据))、3.3.7(冗余录入)、3.3.8(可访问的身份验证)。
- WHATWG HTML 自动填充 — 完整的自动填充标记列表。
- NIST SP 800-63B-4 数字身份指南 — 记忆秘密验证器(密码)指南。
- ARIA 创作实践指南(APG) — combobox 模式。
- web.dev 通行密钥自动填充 — 如何将通行密钥与
autocomplete集成。 - MDN inputmode — 触控键盘类型说明。
- Roselli 2023 aria-errormessage 支持 — 渲染的屏幕阅读器支持数据。
- Wroblewski 2009 表单内联验证 — 最初的展示与设计研究。
- Bargas-Avila 2007 验证时机 — 提交时与即时验证的研究。
- Stripe 幂等性 — 幂等键的 API 设计。
- W3C 国际化(i18n) — 全球姓名格式。