在移动设备上填写表单很困难。输入操作最少的表单就是最好的表单。出色的表单提供有语义的输入类型。按键应变为与用户的输入类型匹配;用户在日历中选取日期。让用户了解最新信息。验证工具应告诉用户,在提交表单之前他们需要做什么。
设计高效的表单
通过避免重复操作、只请求必要的信息来设计高效的表单,并通过向用户显示他们在多部分表单中的操作进度来指引用户。
TL;DR
- 使用现有数据来预填充各字段,并且一定要启用自动填充。
- 使用清楚标示的进度条来帮助用户完成多部分的表单。
- 提供可视化日历,让用户不必离开您的网站,并跳转到其智能手机上的日历应用。
最大程度减少重复的操作和字段

确保表单没有重复操作,只设置必要的字段数量,并利用自动填充,使用户能借助预填充的数据轻松填写表单。
寻找机会预先填充您已知道或可以预判的信息,使用户无需手动输入。 例如,给收货地址预先填充用户上次提供的收货地址。
向用户显示他们的操作进度

进度条和菜单应准确传达多步骤表单和流程的总体进度。如果在早期步骤中设置了异常复杂的表单,用户更可能放弃您的网站,而不会完成整个流程。
在选择日期时提供可视化日历

用户在安排约会和旅行日期时往往需要更多上下文,如要使操作更容易,并防止他们离开您的网站去查看其日历应用,就应提供一个可视化日历,设置清楚的标签以便选择开始和结束日期。
选择最佳输入类型
使用正确的输入类型来简化信息输入操作。用户喜欢在输入电话号码时网站自动显示数字键盘,或随着输入信息自动跳换字段。寻找机会消除表单中的多余点击。
TL;DR
- 选择最适合数据的输入类型,以简化输入操作。
- 通过
datalist
元素在用户输入时提供建议值。
HTML5 输入类型
HTML5 引入了大量新的输入类型。这些新输入类型可以提示浏览器,屏幕键盘应显示什么类型的键盘布局。用户无需切换键盘,就能更轻松地输入所需信息,并且只看到该输入类型的相应按键
输入 type | |
---|---|
url 用于输入网址。其开头必须是有效的 URI 架构,例如 http:// 、 ftp:// 或 mailto: 。 | ![]() |
tel 用于输入电话号码。它不 执行特定的验证语法,因此,如果要确保特定的格式,可以使用模式属性。 | ![]() |
email 用于输入电子邮件地址,并提示键盘上应默认显示 @。 如果需要用户提供多个电子邮件地址,则可以添加 multiple 属性。 | ![]() |
search 一个文本输入字段,其样式与平台的搜索字段一致。 | ![]() |
number 用于数字输入,可以是任意合理的整数或浮点值。 | ![]() |
range 用于数字输入,但与 number 输入类型不同,其值没那么重要。 它以滑块控件的形式显示给用户。 | ![]() |
datetime-local 用于输入日期和时间值,提供的时区为本地时区。 | ![]() |
date 用于只输入日期,不提供时区。 | ![]() |
time 用于只输入时间,不提供时区。 | ![]() |
week 用于只输入星期,不提供时区。 | ![]() |
month 用于只输入月份,不提供时区。 | ![]() |
color 用于选取颜色。 | ![]() |
Note: 请谨记在选择输入类型时要牢记本地化,有些语言区域使用点 (.),而不使用逗号 (,) 来作为分隔符。
使用 datalist 在输入时提供建议值
datalist
元素不是输入类型,而是与一个表单字段关联的建议输入值的列表。 它允许浏览器在用户输入时建议自动填充选项。 datalist
元素与 select 元素不同,它无需用户浏览长列表来找出所需的值,也不限制用户只能选择这些选项,此元素在用户输入时提供提示。
<label for="frmFavChocolate">Favorite Type of Chocolate</label>
<input type="text" name="fav-choc" id="frmFavChocolate" list="chocType">
<datalist id="chocType">
<option value="white">
<option value="milk">
<option value="dark">
</datalist>
Note:datalist
值是提供的建议值,并不意味着用户只能选择所提供的建议值。
正确地为输入设置标签和命名
在移动设备上填写表单很困难。输入操作最少的表单就是最好的表单。出色的表单提供有语义的输入类型。按键应变为与用户的输入类型匹配;用户在日历中选取日期。让用户了解最新信息。验证工具应告诉用户,在提交表单之前他们需要做什么。
TL;DR
- 务必对表单输入使用
label
,并确保字段处于焦点时标签可见。 - 使用
placeholder
来提供有关预期输入内容的指导。 - 为帮助浏览器自动填充表单,为各元素使用既定的
name
并包括autocomplete
属性。
标签的重要性
label
元素为用户提供指引,告诉他们表单元素中需要什么信息。 将输入元素放在 label
元素内,或通过使用“for
”属性,可使每个 label
与一个输入元素关联。为表单元素设置标签还能帮助增大触摸目标的大小:用户可以触摸标签或输入框,以将焦点置于输入元素中。
<label for="frmAddressS">Address</label>
<input type="text" name="ship-address" required id="frmAddressS"
placeholder="123 Any Street" autocomplete="shipping street-address">
标签大小和放置
标签和输入框应足够大,以便点击。在纵向视口中,字段标签应在输入元素上方,在横向视口中则在输入元素旁边。确保字段标签和对应的输入框同时可见。要注意自定义的滚动处理程序,可能会把输入元素滚动到页面顶端而隐藏了标签,或者放在输入元素下方的标签可能会被虚拟键盘所遮挡。
使用占位符
占位符属性可提示用户应在输入框中输入什么内容,通常以浅色文本显示其值,直到用户开始在元素中输入。
<input type="text" placeholder="MM-YYYY" ...>
Note: 当用户开始输入元素时,占位符立即消失,因此它们不能代替标签。应使用占位符作为辅助,引导用户注意所需的格式和内容。
使用元数据来实现自动填充
当网站自动填写一些常见字段(如姓名、电子邮件地址和其他常用字段)为用户节省时间时,用户会很喜欢,并且这样还能帮助减少潜在的输入错误,尤其是在使用虚拟键盘和很小的设备时。
浏览器使用许多启发方法,根据用户之前指定的数据来确定可以自动填充哪些字段,并且您可以为每个输入元素提供 name
属性和 autocomplete
属性来提示浏览器。Note: Chrome 需要将 input
元素包含在 <form>
标记中才能启用自动完成。 如果它们不包含在 form
标签中,Chrome 将提供建议值,但是不会完成表单。
例如,要提示浏览器应给表单自动填写用户名、电子邮件地址和电话号码,应当使用:
<label for="frmNameA">Name</label>
<input type="text" name="name" id="frmNameA"
placeholder="Full name" required autocomplete="name">
<label for="frmEmailA">Email</label>
<input type="email" name="email" id="frmEmailA"
placeholder="name@example.com" required autocomplete="email">
<label for="frmEmailC">Confirm Email</label>
<input type="email" name="emailC" id="frmEmailC"
placeholder="name@example.com" required autocomplete="email">
<label for="frmPhoneNumA">Phone</label>
<input type="tel" name="phone" id="frmPhoneNumA"
placeholder="+1-555-555-1212" required autocomplete="tel">
建议的输入 name
和 autocomplete
属性值
autocomplete
属性值是当前 WHATWG HTML 标准的一部分。下面显示了最常用的 autocomplete
属性。
autocomplete
属性可以附带分区名称,例如 shipping
given-name
或 billing
street-address
。浏览器将单独自动填充不同的分区,而不是将其作为一个连续表单。
内容类型 | name 属性 | autocomplete 属性 |
---|---|---|
名称 | name fname mname lname | name (全名)given-name (名字)additional-name (中间名)family-name (姓氏) |
电子邮件 | email | email |
地址 | address city region province state zip zip2 postal country | 用于单个地址输入框:street-address 用于两个地址输入框:address-line1 address-line2 address-level1 (州或省)address-level2 (城市)postal-code (邮编)country |
电话 | phone mobile country-code area-code exchange suffix ext | tel |
信用卡 | ccname cardnumber cvc ccmonth ccyear exp-date card-type | cc-name cc-number cc-csc cc-exp-month cc-exp-year cc-exp cc-type |
用户名 | username | username |
密码 | password | current-password (用于登录表单)new-password (用于注册和更改密码表单) |
Note: 仅在您的地址格式需要时,才需要使用 street-address
或者 address-line1
和 address-line2address-level1
和 address-level2
。
autofocus
属性
在某些表单上,例如 Google 首页,需要用户做的唯一操作是填写一个特定字段,则可以加上 autofocus
属性。在设置了此属性时,桌面浏览器会立即将焦点移到输入字段,使用户可以轻松快速地开始填写表单。 移动浏览器会忽略 autofocus
属性,以防止键盘随机显示。
要小心使用 autofocus 属性,因为它将侵占键盘焦点,并且可能阻止使用退格符来进行导航。
<input type="text" autofocus ...>
提供实时验证
实时数据验证不仅有助于保持数据清洁,还能改善用户体验。现代浏览器有多种内置工具可提供实时验证,并且能防止用户提交无效的表单。应使用可视化线索来指示表单是否已正确填写。
TL;DR
- 利用浏览器的内置验证属性,例如
pattern
、required
、min
、max
等。 - 使用 JavaScript 和 Constraints Validation API 来满足更复杂的验证要求。
- 实时显示验证错误,如果用户尝试提交无效的表单,则显示他们需要修正的所有字段。
使用以下属性来验证输入值
pattern
属性
pattern
属性指定一个用于验证输入字段的正则表达式。 例如,要验证美国邮编(5 位数,有时后面有一个破折号和另外 4 位数),我们将 pattern
设置如下:
<input type="text" pattern="^\d{5,6}(?:[-\s]\d{4})?$" ...>
常用的正则表达式模式
正则表达式 | |
---|---|
邮寄地址 | [a-zA-Z\d\s\-\,\#\.\+]+ |
邮编(美国) | ^\d{5,6}(?:[-\s]\d{4})?$ |
IP 地址 (IPv4) | ^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ |
IP 地址 (IPv6) | ^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$ |
IP 地址(两种) | ^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$ |
信用卡号 | ^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|6(?:011|5[0-9]{2})[0-9]{12}|(?:2131|1800|35\d{3})\d{11})$ |
社会保障号 | ^\d{3}-\d{2}-\d{4}$ |
北美电话号码 | ^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$ |
required
属性
如果提供 required
属性,则此字段必须包含值,才能提交表单。 例如,要使邮编为必填值,只需加上 required 属性:
<input type="text" required pattern="^\d{5,6}(?:[-\s]\d{4})?$" ...>
min
、max
和 step
属性
对于数字输入类型,如数字或范围以及日期/时间输入,可以指定最小值和最大值,以及在通过滑块或微调框进行调整时的每个增量/减量。例如,鞋码输入将设置最小码 1 和最大码 13,递增或递减单位为 0.5
<input type="number" min="1" max="13" step="0.5" ...>
maxlength
属性
maxlength
属性可用于指定输入值或文本框的最大长度,当您要限制用户可提供信息的长度时,此属性很有用。例如,如果要将文件名限制为 12 个字符,可以使用以下方法。
<input type="text" id="83filename" maxlength="12" ...>
minlength
属性
minlength
属性可用于指定输入值或文本框的最小长度,当您要指定用户必须提供的最小长度时,此属性很有用。例如,如果要指定文件名需要至少 8 个字符,可以使用以下方法。
<input type="text" id="83filename" minlength="8" ...>
novalidate
属性
在某些情况下,即使表单包含无效的输入,您也可能想允许用户提交表单。 为此,可给表单元素或单独的输入字段加上 novalidate
属性。 在这种情况下,所有伪类和 JavaScript API 仍将允许您检查表单是否通过验证。
<form role="form" novalidate> <label for="inpEmail">Email address</label> <input type="email" ...></form>
Success: 即使客户端有输入验证,也务必在服务器上验证数据,以确保数据的一致性和安全性。
使用 JavaScript 实现更复杂的实时验证
当内置验证加上正则表达式还不够时,可以使用 Constraint Validation API,这是一个用于处理自定义验证的强大工具。此 API 使您能够进行各种验证,例如设置自定义错误,检查一个元素是否有效,并确定元素无效的原因:
Constraint Validation | |
---|---|
setCustomValidity() | 设置自定义验证消息,并将 ValidityState 对象的 customError 属性设置为 true 。 |
validationMessage | 返回一个字符串,说明输入值未通过验证测试的原因。 |
checkValidity() | 如果元素满足其所有约束条件,则返回 true ,否则返回 false 。由开发者决定在检查返回 false 时页面如何响应。 |
reportValidity() | 如果元素满足其所有约束条件,则返回 true ,否则返回 false 。当页面响应 false 时,向用户报告约束问题。 |
validity | 返回一个表示元素有效状态的 ValidityState 对象。 |
设置自定义验证消息
如果字段未通过验证,可使用 setCustomValidity()
来将字段标记为无效并解释字段未通过验证的原因。 例如,注册表单可能要求用户通过输入两次来确认其电子邮件地址。 对第二个输入使用 blur 事件,以验证两个输入值,并设置相应的响应。例如:
if (input.value != primaryEmail) {
// the provided value doesn't match the primary email address
input.setCustomValidity('The two email addresses must match.');
console.log("E-mail addresses do not match", primaryEmail, input.value);
} else {
// input is valid -- reset the error message
input.setCustomValidity('');
}
阻止提交无效的表单
由于并非所有浏览器都会在表单存在无效数据时阻止用户提交,因此您应当捕获提交事件,并对表单元素使用 checkValidity()
以确定表单是否有效。
例如:
form.addEventListener("submit", function(evt) {
if (form.checkValidity() === false) {
evt.preventDefault();
alert("Form is invalid - submission prevented!");
return false;
} else {
// To prevent data from being sent, we've prevented submission
// here, but normally this code block would not exist.
evt.preventDefault();
alert("Form is valid - submission prevented to protect privacy.");
return false;
}
});
实时显示反馈
在用户提交表单之前,就在每个字段提供可视指示,提示用户是否已正确填写表单,这样做很有帮助。HTML5 也引入了很多新的伪类,可以用于根据输入值或属性来设置输入的样式。
实时反馈 | |
---|---|
:valid | 明确地设置当输入值符合所有验证要求时,要使用的输入值样式。 |
:invalid | 明确地设置当输入值不符合所有验证要求时,要使用的输入值样式。 |
:required | 明确地设置已设定 required 属性的输入元素的样式。 |
:optional | 明确地设置未设定 required 属性的输入元素的样式。 |
:in-range | 明确地设置在输入值处于范围内时数字输入元素的样式。 |
:out-of-range | 明确地设置在输入值超出范围时数字输入元素的样式。 |
验证是立即进行的,意味着当页面加载时,即使用户尚无机会填写各字段,字段就可能被标记为无效。它还意味着,用户正在输入时就可能看到提示样式无效。 为防止此问题,可以将 CSS 与 JavaScript 结合,只在用户已访问此字段时才显示无效的样式。
input.dirty:not(:focus):invalid {
background-color: #FFD9D9;
}
input.dirty:not(:focus):valid {
background-color: #D9FFD9;
}
var inputs = document.getElementsByTagName("input");
var inputs_len = inputs.length;
var addDirtyClass = function(evt) {
sampleCompleted("Forms-order-dirty");
evt.srcElement.classList.toggle("dirty", true);
};
for (var i = 0; i < inputs_len; i++) {
var input = inputs[i];
input.addEventListener("blur", addDirtyClass);
input.addEventListener("invalid", addDirtyClass);
input.addEventListener("valid", addDirtyClass);
}