利用 HTML5 美化表单

HTML5 Rocks

简介

对表单感兴趣的人并不多,但 HTML5 引入的一些重大改进却同时方便了创建表单的开发人员和填写表单的用户。全新的表单元素、属性、输入类型、基于浏览器的验证、CSS3 样式技术以及 FormData 对象让创建表单变得更轻松,甚至可能更富有趣味性。

There is even more up to date forms guidance on our new Web Fundamentals site.

浏览器支持

在撰写本文时,所有新的表单和输入元素以及属性和类型的支持情况都会因浏览器的不同而存在很大差异。甚至在支持特定功能的各个浏览器之间,它们的行为也会互不相同。但 HTML5 表单的支持情况变化很快,且仍在不断改进。在撰写本文时,这些图表是我能找到的最新图表,它们详细说明了各个浏览器对 HTML5 表单的支持情况。

新增内容概述

新元素

HTML5 引入了 5 种有关输入和表单的新元素。

元素 用途 注释
progress 用于表示任务已完成。 progress 元素可用于表示文件的上传进程。
meter 用于表示已知范围内的标量测量值。 meter 元素可用于表示温度或重量等测量值。
datalist 用于表示一组 option 元素,您可以将这些元素与新输入属性 list 配合使用,以制作下拉菜单。 如果对焦到带有数据表的输入,系统就会显示一个下拉菜单,其中包含 datalist 中的值。
keygen 用于生成密钥对的控件。 提交表单时,系统会将私钥保存在本地密钥库中,并将公钥发送到服务器。
output 用于显示计算结果。 例如,output 元素可用于显示两个输入元素值的总和。

新输入类型

HTML5 引入了 13 种新的输入类型。如果在不支持这些输入类型的浏览器中查看,系统就会使用后备的文字输入。

输入类型 用途 注释
tel 用于输入电话号码。 tel 不执行特定语法,因此如果您想确保特定的格式,可以使用 patternsetCustomValidity() 执行额外的验证。
search 用于提示用户输入要搜索的文字。 searchtext 之间的区别主要在于样式上。使用 search 输入类型可能会导致输入字段的样式与平台的搜索字段相一致。
url 用于输入单个网址。 url 用于输入单个表示很大范围值的绝对网址
email 用于输入单个电子邮件地址或电子邮件地址列表。 如果指定了 multiple 属性,就可以输入多个电子邮件地址,以逗号分隔。
datetime 用于输入时区设置为 UTC 的日期和时间。
date 用于输入不含时区的日期。
month 用于输入含年份和月份但不含时区的日期。
week 用于输入含年份和周数但不含时区的日期。 例如,此格式的日期 2011-W05 表示 2011 年的第 5 周。
time 用于输入含小时、分钟、秒和秒的小数部分但不含时区的时间值。
datetime-local 用于输入不含时区的日期和时间。
number 用于输入数字。 有效值为浮点数
range 用于输入数字,但与 number 的区别在于无需输入具体数字。 在大部分支持该类型的浏览器中,范围控件的实施形式为滑块。
color 用于通过颜色池控件选择颜色。 值必须为有效的小写简单颜色,例如 #ffffff。

新输入属性

HTML5 还为输入和表单元素引入了几种新属性。

属性 用途 注释
autofocus 用于在网页加载后对焦到相关元素上的输入。 autofocus 的目标可以是输入、选择、文本区域和按钮。
placeholder 用于提示用户应输入的数据类型。 在对焦到相关元素以及用户输入数据之前,系统会以浅色文字显示占位符值。您可以在输入和文本区域中指定该值。
form 用于指定输入元素所属的一或多个表单。 借助 form 属性,您可以将输入元素放在网页的任何位置上,而不是只能放在表单元素中。同时,单个输入元素可与多个表单关联。
required 用于表示必填元素的布尔值属性。 required 属性有助于在不使用自定义 JavaScript 的情况下执行基于浏览器的验证。
autocomplete 用于指定浏览器不应根据用户的历史记录自动填充或预先填充某个字段。 autocomplete 属性可用于信用卡号或一次性密码等您不想自动填充的字段。默认情况下,autocomplete 处于 on 状态,因此如果您想停用该属性,请将其设置为 off
pattern 用于根据正则表达式验证元素的值。 在使用 pattern 时,您也应指定 title 值,以便向用户提供预期模式的说明。
dirname 用于随表单提交控件的方向。 例如,如果用户按从右到左的方向输入文本数据,且输入元素包含 dirname 属性,那么系统就会将指明从右到左方向的内容随输入值一起提交。
novalidate 在表单元素上指定该属性即可停用表单提交验证。
formaction 用于覆盖表单元素上的 action 属性。 inputbutton 元素支持此属性。
formenctype 用于覆盖表单元素上的 enctype 属性。 inputbutton 元素支持此属性。
formmethod 用于覆盖表单元素上的 method 属性。 inputbutton 元素支持此属性。
formnovalidate 用于覆盖表单元素上的 novalidate 属性。 inputbutton 元素支持此属性。
formtarget 用于覆盖表单元素上的 target 属性。 inputbutton 元素支持此属性。

FormData 对象

在对 XMLHttpRequest 的多项改进中,有一项是引入了 FormData 对象。借助 FormData 对象,您可以创建并发送一组密钥/值对,也可以选择使用 XMLHttpRequest 创建并发送文件。使用此技术时,数据的发送格式与您通过表单的带 multipart/form-data 编码类型的 submit() 方法提交的数据相同。

FormData 提供了一种方法,供您使用 JavaScript 即时创建 HTML 表单,然后使用 XMLHttpRequest.send() 提交表单。下面是一个简单的示例:

var formData = new FormData();
formData.append("part_num", "123ABC"); 
formData.append("part_price", 7.95);
formData.append("part_image", somefile)

var xhr = new XMLHttpRequest();
xhr.open("POST", "http://some.url/");  
xhr.send(formData);

您也可以在提交表单前使用 FormData 将其他数据添加到现有表单中。

var formElement = document.getElementById("someFormElement");
var formData = new FormData(formElement);
formData.append("part_description", "The best part ever!");

var xhr = new XMLHttpRequest();
xhr.open("POST", "http://some.url/");
xhr.send(formData);

基于浏览器的验证

实话实说吧,验证表单数据是一项十分令人厌烦的任务,但无论如何您都要去做。现在,为了执行客户端表单验证,您可能会编写一些自定义 JavaScript 代码或使用库执行某些操作,例如检查有效输入或在表单提交前确保必填字段均已填写。

与 CSS 伪类选择器配合使用的 requiredpattern 等新输入属性可让您更轻松地编写检查代码并向用户显示反馈。借助其他一些先进的验证技术,您还可以使用 JavaScript 设置自定义验证规则和讯息,或者确定元素是否无效以及无效原因。

required 属性

在提交表单时,带 required 属性的字段必须包含值。以下必填电子邮件地址输入字段的示例用于确保该字段包含一个值,且这个值是有效的电子邮件地址(具体定义请点击此处)。

<input type="email" id="email_addr" name="email_addr" required />

pattern 属性

您可以通过 pattern 属性指定用于验证输入字段的正则表达式。此示例表示一个部件号的必填文本输入字段。在此示例中,我们假设部件号由三个大写字母和紧随其后的四个数字组成。使用 requiredpattern 可确保该字段包含一个值,且这个值符合部件号的正确格式。如果用户将鼠标悬停在该字段上,系统就会显示 title 属性中的讯息。

<input type="text" id="part" name="part" required pattern="[A-Z]{3}[0-9]{4}"
       title="Part numbers consist of 3 uppercase letters followed by 4 digits."/>

在此示例的基础上,如果输入的部件号无效,您也可以将输入字段的边框描成红色。要在值无效的情况下在输入字段周围显示红色边框,请添加以下 CSS。

:invalid {
  border: 2px solid #ff0000;
}

formnovalidate 属性

formnovalidate 属性适用于 inputbutton 元素。使用该属性可停用表单提交验证。在以下示例中,通过“提交”按钮提交表单需要有效输入,但通过“保存”按钮提交则不需要。

<input type="text" id="part" name="part" required pattern="[A-Z]{3}[0-9]{4}"
       title="Part numbers consist of 3 uppercase letters followed by 4 digits."/>
<input type="submit" formnovalidate value="Save">
<input type="submit" value="Submit">

constraint validation API

constraint validation API 为您提供了处理自定义验证的强大工具。您可以通过该 API 执行设置自定义错误、检查元素是否有效以及确定元素无效原因等操作。在以下示例中,如果两个字段中的值不一致,系统就会显示自定义错误。

<label>Email:</label>
<input type="email" id="email_addr" name="email_addr">

<label>Repeat Email Address:</label>
<input type="email" id="email_addr_repeat" name="email_addr_repeat" oninput="check(this)">

<script>
function check(input) {
  if (input.value != document.getElementById('email_addr').value) {
    input.setCustomValidity('The two email addresses must match.');
  } else {
    // input is valid -- reset the error message
    input.setCustomValidity('');
  }
}
</script>

综合使用

以下预订请求表单示例综合使用了各种输入类型、表单验证以及 CSS 选择器和样式。

$99.00

表单的 HTML 和 JavaScript 如下:

<form oninput="total.value = (nights.valueAsNumber * 99) + 
 ((guests.valueAsNumber - 1) * 10)">

  <label>Full name:</label>
  <input type="text" id="full_name" name="full_name" placeholder="Jane Doe" required>

  <label>Email address:</label>
  <input type="email" id="email_addr" name="email_addr" required>

  <label>Repeat email address:</label>
  <input type="email" id="email_addr_repeat" name="email_addr_repeat" required 
   oninput="check(this)">

  <label>Arrival date:</label>
  <input type="date" id="arrival_dt" name="arrival_dt" required>
  
  <label>Number of nights (rooms are $99.00 per night):</label>
  <input type="number" id="nights" name="nights" value="1" min="1" max="30" required>

  <label>Number of guests (each additional guest adds $10.00 per night):</label>
  <input type="number" id="guests" name="guests" value="1" min="1" max="4" required>

  <label>Estimated total:</label>
  $<output id="total" name="total">99</output>.00
  <br><br>

  <label>Promo code:</label>
  <input type="text" id="promo" name="promo" pattern="[A-Za-z0-9]{6}" 
   title="Promo codes consist of 6 alphanumeric characters.">

  <input type="submit" value="Request Reservation" /> 
</form>

<script>
function check(input) {
  if (input.value != document.getElementById('email_addr').value) {
    input.setCustomValidity('The two email addresses must match.');
  } else {
    // input is valid -- reset the error message
    input.setCustomValidity('');
  }
}
</script>

表单代码所带的 CSS 如下:

:invalid { 
  border-color: #e88;
  -webkit-box-shadow: 0 0 5px rgba(255, 0, 0, .8);
  -moz-box-shadow: 0 0 5px rbba(255, 0, 0, .8);
  -o-box-shadow: 0 0 5px rbba(255, 0, 0, .8);
  -ms-box-shadow: 0 0 5px rbba(255, 0, 0, .8);
  box-shadow:0 0 5px rgba(255, 0, 0, .8);
}

:required {
  border-color: #88a;
  -webkit-box-shadow: 0 0 5px rgba(0, 0, 255, .5);
  -moz-box-shadow: 0 0 5px rgba(0, 0, 255, .5);
  -o-box-shadow: 0 0 5px rgba(0, 0, 255, .5);
  -ms-box-shadow: 0 0 5px rgba(0, 0, 255, .5);
  box-shadow: 0 0 5px rgba(0, 0, 255, .5);
}

form {
  width:300px;
  margin: 20px auto;
}

input {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  border:1px solid #ccc;
  font-size:20px;
  width:300px;
  min-height:30px;
  display:block;
  margin-bottom:15px;
  margin-top:5px;
  outline: none;

  -webkit-border-radius:5px;
  -moz-border-radius:5px;
  -o-border-radius:5px;
  -ms-border-radius:5px;
  border-radius:5px;
}

input[type=submit] {
  background:none;
  padding:10px;
}

参考资料

Comments

0