Chrome Dev Summit 2018 is happening now and streaming live on YouTube. Watch now.

建立令人驚艷的表單

手機上很難填寫表單。 最好的表單是輸入量最少的表單。 好的表單應該提供語意式輸入類型。 按鍵應該可以變更以符合使用者的輸入類型;使用者可在日曆中選擇日期。 讓您的使用者瞭若指掌。 驗證工具應該在提交表單之前就告知使用者應該做什麼。

有關建立令人驚歎表單的這些指南總覽,請查看以下影片。

設計高效率表單

要設計高效率表單,請避免重複行為、只要求必要資訊,並向使用者展示其在多部分表單中的進度以引導使用者。

TL;DR

  • 使用現有資料預先填入欄位,並確保啟用自動填寫。
  • 使用標記清楚的進度列,以協助使用者完成多部分表單。
  • 提供視覺化日曆,讓使用者無需離開您的網站,以跳至智慧手機上的日曆應用程式。

儘量減少重複行為和欄位

請確保您的表單沒有重複行為、 只加入必要的欄位數目, 並善用 自動填寫,以便使用者可以利用預先填入資料, 輕鬆完成表單。

在多部分表單中顯示進度
在 Progressive.com 網站上,會先要求使用者提供 ZIP 郵遞區號,然後區號會預先填入到表單的下一部分。

尋找機會預先填寫您已知或預期的資訊, 讓使用者省掉提供資訊的必要性。 例如,以使用者提供的上一次交貨地址, 預先填入交貨地址。

向使用者顯示已完成的進度

進度列和功能表應該透過多步驟表單和程序, 精確傳達整體進度。

在多部分表單中顯示進度
使用標記清楚的進度列,以協助使用者完成多部分表單。

如果您將一個不成比例的複雜表單放在初期步驟, 使用者更有可能在完成整個程序之前,就放棄您的網站。

在選擇日期時提供視覺化日曆

排程約會和旅行日期時, 使用者經常需要更多的前後文資訊。要簡化過程, 並避免使用者離開您的網站以查看其日曆應用程式,請提供一個帶有明確標籤的視覺化日曆, 以選擇開始和結束日期。

具有易用日曆的旅館網站
具有易用日曆小工具的旅館預約網站,方便選擇日期。

選擇最佳輸入類型

使用正確的輸入類型,簡化資訊輸入。 使用者會喜歡自動呈現數字按鍵,以供輸入電話號碼的網站,或是在輸入號碼時自動移至下個欄位。 在您的表單中尋找剔除多餘點選動作的機會。

TL;DR

  • 為您的資料選擇最合適的輸入類型,以簡化輸入。
  • 當使用者以 datalist 元素輸入時,提供建議。

HTML5 輸入類型

HTML5 導入了數種新輸入類型。 這些新的輸入類型可以提示瀏覽器, 有關應為螢幕小鍵盤, 顯示哪種類型的鍵盤。 無需變更鍵盤, 並只看到該輸入類型所需的適當按鍵時, 使用者能更輕鬆地輸入所需的資訊。

輸入 type 一般鍵盤
url
用於輸入 URL。 它必須先以一個有效的 URI 配置開始, 例如 http://, ftp://mailto:
tel
用於輸入電話號碼。 它不會 強制特定語法供驗證, 所以您若要確定特定格式,可以使用模式。
email
用於輸入電子郵件地址, 並提示 @ 應該按預設在鍵盤上顯示。 如果將要提供多個電子郵件地址, 您可以新增多個屬性。
search
文字輸入欄位, 其樣式和平臺的搜尋欄位一致。
number
用於數字輸入, 可以是任何合理的整數或浮點值。
range
用於數字輸入,但與數字輸入類型不同, 此值較不重要。 它是以滑桿控制的形式顯示給使用者。
datetime-local
用於輸入一個日期和時間值, 而提供的時區為當地時區。
date
用於輸入日期 (僅限), 不提供時區。
time
用於輸入時間 (僅限), 不提供時區。
week
用於輸入週 (僅限), 不提供時區。
month
用於輸入月份 (僅限), 不提供時區。
color
用於選擇一種顏色。

以 datalist 輸入時提供建議

datalist 元素不是一種輸入類型, 而是關聯表單欄位的建議輸入值之清單。 它可以在使用者輸入時, 讓瀏覽器顯示自動完成選項。 使用者在選取元素時必須掃描一長串清單尋找值, 並限制只能使用清單上的項目,與其不同的是, datalist 元素會在使用者輸入時提供提示。

<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>

手機上很難填寫表單。 最好的表單是輸入量最少的表單。 好的表單應該提供語意式輸入類型。 按鍵應該可以變更以符合使用者的輸入類型;使用者可在日曆中選擇日期。 讓您的使用者瞭若指掌。 驗證工具應該在提交表單之前就告知使用者應該做什麼。

標籤的重要性

label 元素為使用者提供方向, 告之它們表單元素中需要什麼資訊。 每個 label 與一個輸入元素關聯, 方法是將之放在 label 元素內,或使用「for」屬性。 套用標籤至表單元素也有助於改善輕觸目標的大小: 使用者可以輕觸標籤或輸入,以將焦點放在輸入元素上。

<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" ...>

一旦焦點放在元素中時,預留位置就會消失,因此預留位置不可取代標籤。 預留位置應該當做輔助工具,協助指導使用者使用所需的格式和內容。

使用中繼資料來啟用自動完成

透過自動填寫如姓名、電子郵件地址和其他常用欄位等常見欄位, 使用者會喜歡網站幫他們節省時間; 再加上如此也可減少潛在的輸入錯誤 -- 尤其是在虛擬鍵盤與小型裝置上。

瀏覽器使用許多啟發法來判斷它們可以 (https://support.google.com/chrome/answer/142893){: .external} [根據使用者先前指定的資料] (https://support.google.com/chrome/answer/142893){: .external}[自動填入]哪些欄位 ,您可以提供提示給瀏覽器, 方法是在每一項輸入元素上提供 name 與 autocomplete 屬性。

例如要提示瀏覽器,它應該以使用者名稱、電子郵件地址和電話號碼自動完成表單時, 您應該使用:

<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">

建議輸入 nameautocomplete 屬性值

autocomplete 屬性值是目前 WHATWG HTML 標準的一部分。 最常用的 autocomplete 屬性如下所示:

autocomplete 屬性可以伴隨區段名稱,如 shippinggiven-namebillingstreet-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

當表單方法為 post 時,自動完成才有效。

autofocus 屬性

在某些表單上,例如 Google 首頁上,您要使用者做的唯一一件事就是填寫特定欄位, 此時您可以新增 autofocus 屬性。 當設定時,桌面瀏覽器會立即將焦點移動到輸入欄位, 便於使用者快速開始使用該表單。 行動瀏覽器會忽略 autofocus 屬性,以防止鍵盤隨機出現。

要小心使用自動焦點屬性, 因為它可能偷走鍵盤焦點, 並防止倒退鍵字元用於導覽。

<input type="text" autofocus ...>

title: "提供即時驗證" updated_on: 2014-10-21 key-takeaways: provide-real-time-validation: - 利用瀏覽器的內建驗證屬性,如patternrequiredminmax等。 - 使用 JavaScript 和 Constraints Validation API 於更複雜的驗證要求上。 - 以即時方式顯示驗證錯誤,而且如果使用者嘗試提交無效的表單,就顯示他們必須修正的所有欄位。 notes: use-placeholders: -一旦焦點放在元素中時,預留位置就會消失,因此預留位置不可取代標籤。 預留位置應該當做輔助工具,協助指導使用者使用所需的格式和內容。 recommend-input: - 當表單方法為 post 時,自動完成才有效。 use-datalist: - datalist 值是以建議項目的方式提供,而使用者並不侷限於所提供的建議。 provide-real-time-validation: - 即使以用戶端輸入驗證,需記得一件非常重要的事,請驗證伺服器上的資料,以確保您資料的一致性和安全性。 show-all-errors: - 您應該向使用者一次性顯示表單上的所有問題,而非一次展示一個問題。 request-auto-complete-flow: - 如果您要求任何種類的個人資訊或信用卡資料,確保是透過 SSL 提供頁面。 否則對話方塊中將警告使用者,他們的資訊可能不安全。


即時資料驗證不但能協助保持您的資料乾淨,還有助於改善使用者體驗。 最新瀏覽器具有幾個內建工具,可協助提供即時資料驗證,以防止使用者提交無效的表單。 應使用視覺提示,以表明一張表單是否已正確完成。

即使以用戶端輸入驗證,需記得一件非常重要的事,請驗證伺服器上的資料,以確保您資料的一致性和安全性。

使用這些屬性來驗證輸入

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 屬性存在, 則提交表單之前,欄位必須包含一個值。 例如,要讓郵遞區號成為必要條件, 我們只要新增必要的屬性:

<input type="text" required pattern="^\d{5,6}(?:[-\s]\d{4})?$" ...>
minmaxstep屬性

對於數字或範圍等數字輸入類型, 以及日期/時間輸入,您可以指定最小值和最大值, 以及被滑桿或微調按鈕調整時的增/減量。 例如,鞋子大小輸入會設定最小值為 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

當內建的驗證再加上規則運算式還不夠用的時候, 您可以用 [Constraints Validation API] (https://w3c.github.io/html/sec-forms.html#constraints){: .external}這項強大的工具,以處理自訂驗證。 此 API 可讓您執行如設定自訂錯誤、 檢查元素是否有效, 並判斷元素無效的原因等動作:

API 描述
setCustomValidity() 將自訂驗證訊息和 ValidityState 物件的 customError 屬性設定為 true
validationMessage 傳回一個字串與輸入未能通過驗證測試的原因。
checkValidity() 如果元素滿足所有限制,則傳回 true,否則傳回 false。 決定當檢查傳回 false 時網頁如何回應的問題,將交由開發人員處理。
reportValidity() 如果元素滿足所有限制,則傳回 true,否則傳回 false。 當網頁回應 false 時,限制問題會回報給使用者。
validity 傳回一個 ValidityState 物件,代表元素的有效狀態。
設定自訂驗證訊息

如果一個欄位驗證失敗,請使用 setCustomValidity() ,以標記欄位為無效, 並解釋欄位為何無法通過驗證。 例如,註冊表單可能會要求使用者輸入兩次, 以確認電子郵件地址是否正確。 對第二個輸入使用模糊 事件,以驗證這兩個輸入,並設定適當的 回應。 例如:

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 針對設定了必要屬性的輸入元素,明確設定樣式。
:optional 針對未設定必要屬性的輸入元素,明確設定樣式。
: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);
}

您應該向使用者一次性顯示表單上的所有問題,而非一次展示一個問題。

以 requestAutocomplete API 簡化結帳

雖然 requestAutocomplete 原始設計是為了協助使用者填寫任何表單,但時下最常見的用途是在電子商務中,當行動網路上 放棄購物車商品率可高達 97% 之際。 想像一下超市中有 97% 的人推著滿滿商品的購物車,突然就把車翻倒並走出門。

TL;DR

  • requestAutocomplete 可大大簡化結帳過程,並改善使用者體驗。
  • 如果 requestAutocomplete 可供使用,請隱藏結帳表單,並將人們直接移往確認頁。
  • 確保輸入欄位包含適當的自動完成的屬性。

網站不必依賴特定的付款服務提供者, requestAutocomplete 會向瀏覽器要求付款詳細資料 (如姓名、地址和信用卡資訊); 這些資訊很像其他自動完成欄位一樣,是由瀏覽器選擇性儲存。

requestAutocomplete 流程

最理想的體驗是顯示 requestAutocomplete 對話方塊, 而非載入顯示結帳表單的網頁。 如果一切順利, 使用者應該不會看到任何表單。 您可以輕鬆新增 requestAutocomplete 至現有表單, 而不必變更任何欄位名稱。 只需以適當的值,將 autocomplete 屬性新增至每個表單元素,並在表單元素上加入 requestAutocomplete() 函數。 瀏覽器將處理剩下的操作。

請求自動完成流程

var doRAC = document.getElementById("doRAC");
doRAC.addEventListener("click", doRequestAutocomplete);

form = document.getElementById("usrForm");
form.addEventListener("autocompleteerror", requestAutocompleteError);
form.addEventListener("autocomplete", requestAutocompleteCompleted);

if (form.requestAutocomplete) {
  isRACSupported(true, "");
} else {
  isRACSupported(false, "Please complete the form manually.");
}

form 元素上的 requestAutocomplete 函數向瀏覽器指示, 它應填入表單。 作為安全目的, 函數必須透過輕觸或滑鼠按一下等使用者手勢來呼叫。 然後會顯示對話方塊, 向使用者要求填入欄位的權限,以及要以哪些詳細資料來填入欄位。

function requestAutocompleteCompleted(evt) {
  console.log("requestAutocomplete Completed", evt);
  form.classList.toggle("hidden", false);
}

function requestAutocompleteError(evt) {
  console.log("requestAutocomplete Error", evt);
  isRACSupported(false, "An error occurred attempting to autocomplete the form.");
}

requestAutocomplete 完成的同時,此函數將觸發 autocomplete 事件 (如果它成功完成),或 autocompleteerror (如果未能完成表單)。 如果它成功完成,而表單也驗證您的需求, 只要提交表單並繼續到最終確認步驟即可。