如何構建 Web 表單
在掌握基本知識的基礎上,我們現在將更詳細地瞭解用於為表單的不同部分提供結構和意義的元素。
| 先決條件 | 對 HTML 的基本瞭解。 |
|---|---|
| 目標 | 瞭解如何構建 HTML 表單併為其賦予語義,使其可用且可訪問。 |
表單的靈活性使其成為 HTML 中最複雜的結構之一;您可以使用專用表單元素和屬性構建任何型別的基本表單。在構建 HTML 表單時使用正確的結構將有助於確保表單既可用又 可訪問。
<form> 元素
<form> 元素正式定義了一個表單及其確定表單行為的屬性。每次您要建立 HTML 表單時,您都必須使用此元素開始,將所有內容巢狀在其中。許多輔助技術和瀏覽器外掛可以發現 <form> 元素並實施特殊鉤子以使其更容易使用。
我們在上一篇文章中已經遇到了這個。
警告:嚴格禁止將一個表單巢狀在另一個表單中。巢狀會導致表單的行為不可預測,因此這是一個不好的主意。
始終可以使用表單控制元件在 <form> 元素之外。如果您這樣做,預設情況下,該控制元件與任何表單無關,除非您使用其 form 屬性將其與表單關聯。這是為了讓您顯式地將控制元件繫結到表單,即使它沒有巢狀在其中。
讓我們繼續前進,介紹您將在表單中巢狀的結構元素。
<fieldset> 和 <legend> 元素
<fieldset> 元素是建立具有相同目的的部件組的便捷方法,用於樣式和語義目的。您可以透過在開啟的 <fieldset> 標記下方包含一個 <legend> 元素來標記 <fieldset>。 <legend> 的文字內容正式描述了它所包含的 <fieldset> 的目的。
許多輔助技術將 <legend> 元素視為對應 <fieldset> 元素中每個控制元件標籤的一部分。例如,一些螢幕閱讀器,例如 Jaws 和 NVDA 將在朗讀每個控制元件的標籤之前朗讀圖例的內容。
這是一個小例子
<form>
<fieldset>
<legend>Fruit juice size</legend>
<p>
<input type="radio" name="size" id="size_1" value="small" />
<label for="size_1">Small</label>
</p>
<p>
<input type="radio" name="size" id="size_2" value="medium" />
<label for="size_2">Medium</label>
</p>
<p>
<input type="radio" name="size" id="size_3" value="large" />
<label for="size_3">Large</label>
</p>
</fieldset>
</form>
注意:您可以在 fieldset-legend.html 中找到此示例 (也請檢視線上版本).
在朗讀上述表單時,螢幕閱讀器將為第一個部件朗讀“果汁尺寸小”,為第二個朗讀“果汁尺寸中”,為第三個朗讀“果汁尺寸大”。
此示例中的用例是最重要的用例之一。每次您有一組單選按鈕時,都應將它們巢狀在 <fieldset> 元素中。還有其他用例,一般來說, <fieldset> 元素也可以用來對錶單進行分段。理想情況下,長表單應該分佈在多個頁面上,但如果表單很長且必須在一個頁面上,將不同的相關部分放在不同的欄位集中可以提高可用性。
由於它對輔助技術的影響, <fieldset> 元素是構建可訪問表單的關鍵元素之一;但是,您有責任不要濫用它。如果可能,每次您構建表單時,都嘗試 聽聽螢幕閱讀器 如何解釋它。如果聽起來很奇怪,請嘗試改進表單結構。
<label> 元素
正如我們在上一篇文章中看到的, <label> 元素是正式定義 HTML 表單部件標籤的方法。如果您想構建可訪問的表單,這是最重要的元素——當正確實現時,螢幕閱讀器會朗讀表單元素的標籤以及任何相關的說明,同時它對有視力的使用者也很有用。以這個例子為例,我們在上一篇文章中看到了這個例子
<label for="name">Name:</label> <input type="text" id="name" name="user_name" />
透過 <label> 透過其 for 屬性(其中包含 <input> 元素的 id 屬性)與 <input> 正確關聯,螢幕閱讀器將朗讀類似“姓名,編輯文字”的內容。
還有一種將表單控制元件與標籤關聯的方法——將表單控制元件巢狀在 <label> 中,隱式關聯它。
<label for="name">
Name: <input type="text" id="name" name="user_name" />
</label>
但是,即使在這種情況下,也建議設定 for 屬性以確保所有輔助技術都能理解標籤和部件之間的關係。
如果沒有標籤,或者表單控制元件沒有隱式或顯式與標籤關聯,螢幕閱讀器將朗讀類似“編輯文字空白”的內容,這根本沒有幫助。
標籤也可以點選!
設定正確的標籤的另一個優點是,您可以單擊或點選標籤以啟用相應的部件。這對文字輸入等控制元件很有用,您可以單擊標籤和輸入來聚焦它,但它對單選按鈕和複選框特別有用——此類控制元件的點選區域可能非常小,因此使它儘可能容易啟用非常有用。
例如,單擊下面示例中的“我喜歡櫻桃”標籤文字將切換 taste_cherry 複選框的選擇狀態
<form>
<p>
<input type="checkbox" id="taste_1" name="taste_cherry" value="cherry" />
<label for="taste_1">I like cherry</label>
</p>
<p>
<input type="checkbox" id="taste_2" name="taste_banana" value="banana" />
<label for="taste_2">I like banana</label>
</p>
</form>
注意:您可以在 checkbox-label.html 中找到此示例 (也請檢視線上版本).
多個標籤
嚴格來說,您可以在一個部件上放置多個標籤,但這並不是一個好主意,因為某些輔助技術可能無法處理它們。在存在多個標籤的情況下,您應該將部件及其標籤巢狀在一個 <label> 元素中。
讓我們考慮這個例子
<p>Required fields are followed by <span aria-label="required">*</span>.</p>
<!-- So this: -->
<!--div>
<label for="username">Name:</label>
<input id="username" type="text" name="username" required>
<label for="username"><span aria-label="required">*</label>
</div-->
<!-- would be better done like this: -->
<!--div>
<label for="username">
<span>Name:</span>
<input id="username" type="text" name="username" required>
<span aria-label="required">*</span>
</label>
</div-->
<!-- But this is probably best: -->
<div>
<label for="username">Name: <span aria-label="required">*</span></label>
<input id="username" type="text" name="username" required />
</div>
頂部的段落陳述了必填元素的規則。該規則必須在使用之前包含,以便有視力的使用者和使用螢幕閱讀器等輔助技術的使用者在遇到必填元素之前瞭解其含義。雖然這有助於告知使用者星號的含義,但不能依賴於它。螢幕閱讀器在遇到星號時會將其朗讀為“星號”。當有視力的滑鼠使用者懸停時,應該顯示“必填”,這是透過使用 title 屬性實現的。標題是否朗讀取決於螢幕閱讀器的設定,因此更可靠的做法是也包括 aria-label 屬性,該屬性始終被螢幕閱讀器朗讀。
上述變體隨著您的使用而變得越來越有效
- 在第一個示例中,標籤根本沒有與輸入一起朗讀——您只得到“編輯文字空白”,以及單獨朗讀的實際標籤。多個
<label>元素使螢幕閱讀器感到困惑。 - 在第二個示例中,事情變得更加清晰——與輸入一起朗讀的標籤是“姓名星號姓名編輯文字必填”,標籤仍然被單獨朗讀。事情仍然有點混亂,但這次稍微好一些,因為
<input>與標籤相關聯。 - 第三個示例是最好的——實際標籤被全部朗讀,與輸入一起朗讀的標籤是“姓名必填編輯文字”。
注意:您可能會得到略有不同的結果,具體取決於您的螢幕閱讀器。這在 VoiceOver 中進行了測試(NVDA 的行為類似)。我們也很樂意聽到您的體驗。
注意:您可以在 GitHub 上找到此示例,名為 required-labels.html (也請檢視線上版本). 不要使用 2 或 3 個版本中的其中一個未註釋的版本測試示例——如果您有多個標籤和多個具有相同 ID 的輸入,螢幕閱讀器肯定會感到困惑!
與表單一起使用的常見 HTML 結構
除了特定於 Web 表單的結構之外,還應該記住表單標記只是 HTML。這意味著您可以使用 HTML 的所有功能來構建 Web 表單。
正如您在示例中看到的,將標籤及其部件與 <li> 元素一起包裝在 <ul> 或 <ol> 列表中是常見的做法。 <p> 和 <div> 元素也經常使用。建議使用列表來構建多個複選框或單選按鈕。
除了 <fieldset> 元素之外,使用 HTML 標題(例如 h1, h2)和分段(例如 <section>)來構建複雜表單也是常見的做法。
最重要的是,您可以找到一種舒適的編碼風格,從而建立可訪問且可用的表單。每個單獨的功能部分都應該包含在一個單獨的 <section> 元素中,其中包含 <fieldset> 元素來包含單選按鈕。
主動學習:構建表單結構
讓我們將這些想法付諸實踐,構建一個稍微複雜一些的表單——支付表單。此表單將包含許多您可能還不瞭解的控制元件型別。現在不用擔心;您將在下一篇文章 (基本原生表單控制元件) 中瞭解它們的工作原理。現在,在按照以下說明操作時仔細閱讀說明,並開始瞭解我們正在使用哪些包裝器元素來構建表單,以及為什麼。
- 首先,在您的計算機上的新目錄中,製作我們 空白模板檔案 的本地副本。
- 接下來,透過新增
<form>元素來建立您的表單html<form> - 在
<form>元素中,新增標題和段落以告知使用者必填欄位的標記方式html<h1>Payment form</h1> <p> Required fields are followed by <strong><span aria-label="required">*</span></strong>. </p> - 接下來,我們將向表單新增一個更大的程式碼段,放在我們之前條目的下方。在這裡,您將看到我們正在將聯絡資訊欄位包裝在一個單獨的
<section>元素中。此外,我們有一組三個單選按鈕,我們每個按鈕都放在自己的列表 (<li>) 元素中。我們還有兩個標準文字<input>及其關聯的<label>元素,每個元素都包含在一個<p>中,以及一個用於輸入密碼的密碼輸入。將此程式碼新增到您的表單中html<section> <h2>Contact information</h2> <fieldset> <legend>Title</legend> <ul> <li> <label for="title_1"> <input type="radio" id="title_1" name="title" value="A" /> Ace </label> </li> <li> <label for="title_2"> <input type="radio" id="title_2" name="title" value="K" /> King </label> </li> <li> <label for="title_3"> <input type="radio" id="title_3" name="title" value="Q" /> Queen </label> </li> </ul> </fieldset> <p> <label for="name"> <span>Name: </span> <strong><span aria-label="required">*</span></strong> </label> <input type="text" id="name" name="username" required /> </p> <p> <label for="mail"> <span>Email: </span> <strong><span aria-label="required">*</span></strong> </label> <input type="email" id="mail" name="usermail" required /> </p> <p> <label for="pwd"> <span>Password: </span> <strong><span aria-label="required">*</span></strong> </label> <input type="password" id="pwd" name="password" required /> </p> </section> - 表單的第二個 `<section>` 是支付資訊。我們有三個獨立的控制元件及其標籤,每個都包含在 `<p>` 內。第一個是用於選擇信用卡型別的下拉選單 (
<select>)。第二個是型別為 `tel` 的 `<input>` 元素,用於輸入信用卡號碼;雖然我們可以使用 `number` 型別,但我們不想要數字的旋轉器 UI。最後一個是型別為 `text` 的 `<input>` 元素,用於輸入卡的有效期;這包括一個表示正確格式的 *佔位符* 屬性,以及一個測試輸入日期是否具有正確格式的 *模式*。這些較新的輸入型別在 HTML5 輸入型別 中重新介紹。在上一節下面輸入以下內容html<section> <h2>Payment information</h2> <p> <label for="card"> <span>Card type:</span> </label> <select id="card" name="usercard"> <option value="visa">Visa</option> <option value="mc">Mastercard</option> <option value="amex">American Express</option> </select> </p> <p> <label for="number"> <span>Card number:</span> <strong><span aria-label="required">*</span></strong> </label> <input type="tel" id="number" name="cardnumber" required /> </p> <p> <label for="expiration"> <span>Expiration date:</span> <strong><span aria-label="required">*</span></strong> </label> <input type="text" id="expiration" name="expiration" required placeholder="MM/YY" pattern="^(0[1-9]|1[0-2])\/([0-9]{2})$" /> </p> </section> - 我們將新增的最後一個部分要簡單得多,只包含一個
<button>,型別為 `submit`,用於提交表單資料。現在將此新增到表單的底部html<section> <p> <button type="submit">Validate the payment</button> </p> </section> - 最後,透過新增外部
<form>結束標籤來完成表單html</form>
我們對下面完成的表單應用了一些額外的 CSS。如果您想更改表單的外觀,可以從 示例 中複製樣式,或者訪問 樣式化 Web 表單。
測試您的技能!
您已經到達本文的結尾,但您能記住最重要的資訊嗎?在繼續之前,您可以找到一個進一步的測試來驗證您是否保留了這些資訊——請參見 測試您的技能:表單結構。
總結
您現在擁有了正確構建 Web 表單所需的所有知識。我們將在接下來的幾篇文章中介紹這裡介紹的許多功能,下一篇文章將更詳細地介紹如何使用所有不同型別的表單小部件來從您的使用者那裡收集資訊。