创建出色的表单
作者:Pete LePage
在移动设备上填写表单很困难。输入操作最少的表单就是最好的表单。出色的表单提供有语义的输入类型。按键应变为与用户的输入类型匹配;用户在日历中选取日期。让用户了解最新信息。验证工具应告诉用户,在提交表单之前他们需要做什么。
设计高效的表单
通过避免重复操作、只请求必要的信息来设计高效的表单,并通过向用户显示他们在多部分表单中的操作进度来指引用户。
TL;DR
- 使用现有数据来预填充各字段,并且一定要启用自动填充。
- 使用清楚标示的进度条来帮助用户完成多部分的表单。
- 提供可视化日历,让用户不必离开您的网站,并跳转到其智能手机上的日历应用。
最大程度减少重复的操作和字段
在 Progressive.com 网站上,首先要求用户输入邮编,然后邮编会被预填充到表单的下一部分。
确保表单没有重复操作,只设置必要的字段数量,并利用自动填充,使用户能借助预填充的数据轻松填写表单。
寻找机会预先填充您已知道或可以预判的信息,使用户无需手动输入。 例如,给收货地址预先填充用户上次提供的收货地址。
向用户显示他们的操作进度
使用清楚标示的进度条来帮助用户完成多部分的表单。
进度条和菜单应准确传达多步骤表单和流程的总体进度。
如果在早期步骤中设置了异常复杂的表单,用户更可能放弃您的网站,而不会完成整个流程。
在选择日期时提供可视化日历
酒店预订网站,有易用的日历小工具供选择日期。
用户在安排约会和旅行日期时往往需要更多上下文,如要使操作更容易,并防止他们离开您的网站去查看其日历应用,就应提供一个可视化日历,设置清楚的标签以便选择开始和结束日期。
选择最佳输入类型
使用正确的输入类型来简化信息输入操作。用户喜欢在输入电话号码时网站自动显示数字键盘,或随着输入信息自动跳换字段。寻找机会消除表单中的多余点击。
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 用于选取颜色。 |
注意:请谨记在选择输入类型时要牢记本地化,有些语言区域使用点 (.),而不使用逗号 (,) 来作为分隔符。
使用 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>
注: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" ...>
注意:当用户开始输入元素时,占位符立即消失,因此它们不能代替标签。应使用占位符作为辅助,引导用户注意所需的格式和内容。
使用元数据来实现自动填充
当网站自动填写一些常见字段(如姓名、电子邮件地址和其他常用字段)为用户节省时间时,用户会很喜欢,并且这样还能帮助减少潜在的输入错误,尤其是在使用虚拟键盘和很小的设备时。
浏览器使用许多启发方法,根据用户之前指定的数据来确定可以自动填充哪些字段,并且您可以为每个输入元素提供name
属性和autocomplete
属性来提示浏览器。
注: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="[email protected]" required autocomplete="email">
<label for="frmEmailC">Confirm Email</label>
<input type="email" name="emailC" id="frmEmailC"
placeholder="[email protected]" 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
属性可以附带分区名称,例如shippinggiven-name
或billingstreet-address
。浏览器将单独自动填充不同的分区,而不是将其作为一个连续表单。
内容类型 | name属性 | autocomplete属性 |
---|---|---|
名称 | namefnamemnamelname |
name (全名)given-name (名字)additional-name (中间名)、family-name (姓氏) |
电子邮件 | email |
email |
地址 | addresscityregionprovincestatezipzip2postalcountry |
用于单个地址输入框:street-address 用于两个地址输入框:address-line1、address-line2、address-level1 (州或省)address-level2 (城市)postal-code (邮编)country |
电话 | phonemobilecountry-codearea-codeexchangesuffixext |
tel |
信用卡 | ccnamecardnumbercvcccmonthccyearexp-datecard-type |
cc-namecc-numbercc-csccc-exp-monthcc-exp-yearcc-expcc-type |
用户名 | username |
username |
密码 | password |
current-password (用于登录表单)new-password (用于注册和更改密码表单) |
注:仅在您的地址格式需要时,才需要使用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>
成功:即使客户端有输入验证,也务必在服务器上验证数据,以确保数据的一致性和安全性。
使用 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);
}
成功:应一次性向用户显示表单上的所有问题,而不是一次显示一个问题。