HTML 表格可訪問性

在上一篇文章中,我們探討了使 HTML 表格對視障使用者可訪問的最重要特性之一——<th> 元素。在本文中,我們將繼續沿著這條道路,探討更多 HTML 表格可訪問性特性,例如標題/摘要、將行分組到表頭、表體和表腳部分,以及設定列和行的作用域。

預備知識 HTML 基礎知識(參見基本 HTML 語法)。
學習成果
  • 瞭解與表格相關的可訪問性問題。
  • 為表格新增標題。
  • 透過表頭、表體和表腳更好地構建表格。
  • 使用 scopeidheaders 屬性在表頭和單元格之間建立進一步的關聯。

回顧:視障使用者的表格

讓我們簡要回顧一下如何使用資料表。表格是一個方便的工具,可以讓我們快速訪問資料並查詢不同的值。例如,只需快速瀏覽一下下表,就能找出 2016 年 8 月在根特售出了多少個戒指。為了理解其資訊,我們會在該表中的資料與列和/或行標題之間建立視覺關聯。

2016 年 8 月銷售的商品
服裝 配飾
褲子 裙子 連衣裙 手鐲 戒指
比利時 安特衛普 56 22 43 72 23
根特 46 18 50 61 15
布魯塞爾 51 27 38 69 28
荷蘭 阿姆斯特丹 89 34 69 85 38
烏得勒支 80 12 43 36 19

但是如果你無法建立這些視覺關聯呢?那麼你如何閱讀上面的表格呢?視障人士通常使用螢幕閱讀器來為他們讀出網頁上的資訊。當你閱讀純文字時,這不是問題,但解釋表格對盲人來說可能是一個相當大的挑戰。然而,透過適當的標記,我們可以用程式化的關聯替換視覺關聯。

注意:根據世衛組織 2017 年的資料,約有 2.53 億人患有視力障礙。

使用列和行標題

螢幕閱讀器將識別所有標題,並使用它們在這些標題與它們相關的單元格之間建立程式化的關聯。列和行標題的組合將識別和解釋每個單元格中的資料,以便螢幕閱讀器使用者能夠像有視力使用者一樣解釋表格。

我們已經在上一篇文章中介紹了標題——請參閱使用 <th> 元素新增標題

使用 <caption> 為表格新增標題

您可以透過將表格標題放在 <caption> 元素中,並將其巢狀在 <table> 元素中來為表格新增標題。您應該將其放在開啟 <table> 標籤的正下方。

html
<table>
  <caption>
    Dinosaurs in the Jurassic period
  </caption>

  …
</table>

正如您從上面的簡短示例中可以推斷出的那樣,標題旨在包含表格內容的描述。這對於所有希望在瀏覽頁面時快速瞭解表格是否對他們有用的讀者都很有用,尤其是對於盲人使用者。使用者無需讓螢幕閱讀器讀出許多單元格的內容來了解表格的內容,而是可以依靠標題,然後決定是否更詳細地閱讀表格。

標題直接放在 <table> 標籤下方。

注意: summary 屬性也可以用於 <table> 元素來提供描述——螢幕閱讀器也會讀出它。但是,我們建議改用 <caption> 元素,因為 summary 已棄用,並且視力正常的讀者無法閱讀它(它不會出現在頁面上)。

表格標題練習

現在,我們將讓您嘗試為 HTML 表格新增標題,以語言教師的課程表為例。

  1. 在本地複製我們的 timetable-fixed.html 檔案。
  2. 為表格新增一個合適的標題。
  3. 儲存程式碼並在瀏覽器中開啟以檢視其外觀。
點選此處顯示解決方案

您完成的 HTML 應該看起來像這樣

html
<table>
  <caption>
    Florence's weekly lesson timetable
  </caption>
  <colgroup>
    <col span="2" />
    <col style="background-color: #97DB9A;" />
    <col style="width: 42px;" />
    <col style="background-color: #97DB9A;" />
    <col style="background-color: #DCC48E; border: 4px solid #C1437A;" />
    <col span="2" style="width: 42px;" />
  </colgroup>
  <tr>
    <!-- Rest of code omitted for brevity -->
  </tr>
</table>

您可以在 GitHub 上找到此程式碼:timetable-caption.html也可以檢視其現場執行情況)。

使用 <thead>、<tbody> 和 <tfoot> 新增結構

隨著表格結構變得更加複雜,為其提供更多結構定義會很有用。一種明確的方法是使用 <thead><tbody><tfoot>,它們允許您標記表格的表頭、表體和表腳部分。

這些元素不一定會使螢幕閱讀器使用者更容易訪問表格。它們本身不會產生任何視覺增強,但它們對於透過 CSS 應用樣式和佈局增強非常有用,這可以提高可訪問性。舉一些有趣的例子,對於長表格,您可以讓表格的表頭和表腳在每個列印頁面上重複出現,並且可以讓表格主體顯示在一個頁面上,並透過上下滾動來檢視內容。

要使用它們,它們應該按以下順序包含

  • <thead> 元素必須包裹表格的表頭部分——這通常是包含列標題的第一行,但並非總是如此。如果您正在使用 <col>/<colgroup> 元素,則表格表頭應緊隨其後。
  • <tbody> 元素需要包裹表格內容中除表頭或表腳之外的主要部分。
  • <tfoot> 元素需要包裹表格的表腳部分——例如,這可能是一個包含前幾行專案總和的最後一行。

注意: <tbody> 總是包含在每個表格中,如果您在程式碼中沒有明確指定它,它也會隱式存在。要驗證這一點,請開啟您之前不包含 <tbody> 的一個示例,並在您的瀏覽器開發者工具中檢視 HTML 程式碼——您會看到瀏覽器已為您添加了此標籤。您可能想知道為什麼還要費心包含它——您應該這樣做,因為它為您提供了對錶格結構和樣式的更多控制。

為消費記錄表新增結構

讓我們讓您將這些新元素付諸實踐。

  1. 首先,在新的資料夾中複製 spending-record.htmlminimal-table.css 的本地副本。

  2. 嘗試將明顯的標題行放在 <thead> 元素內,將“SUM”行放在 <tfoot> 元素內,並將其餘內容放在 <tbody> 元素內。

  3. 接下來,新增一個 colspan 屬性,使“SUM”單元格跨越前四列,以便實際數字出現在“成本”列的底部。

  4. 讓我們為表格新增一些簡單的額外樣式,讓您瞭解這些元素對於應用 CSS 是多麼有用。在 HTML 文件的頭部,您會看到一個空的 <style> 元素。在此元素內部,新增以下 CSS 程式碼行

    css
    tbody {
      font-size: 95%;
      font-style: italic;
    }
    
    tfoot {
      font-weight: bold;
    }
    

    注意:我們不期望您現在完全理解 CSS。您將在學習我們的 CSS 模組時瞭解更多資訊(從CSS 樣式基礎開始,其中包括一篇專門針對表格樣式的文章)。

  5. 儲存並重新整理,然後檢視結果。如果 <tbody><tfoot> 元素不存在,您將不得不編寫更復雜的選擇器/規則來應用相同的樣式。

點選此處顯示解決方案

您完成的 HTML 應該看起來像這樣

html
<table>
  <caption>
    How I chose to spend my money
  </caption>
  <thead>
    <tr>
      <th>Purchase</th>
      <th>Location</th>
      <th>Date</th>
      <th>Evaluation</th>
      <th>Cost (€)</th>
    </tr>
  </thead>
  <tfoot>
    <tr>
      <td colspan="4">SUM</td>
      <td>118</td>
    </tr>
  </tfoot>
  <tbody>
    <tr>
      <td>Haircut</td>
      <td>Hairdresser</td>
      <td>12/09</td>
      <td>Great idea</td>
      <td>30</td>
    </tr>
    <tr>
      <td>Lasagna</td>
      <td>Restaurant</td>
      <td>12/09</td>
      <td>Regrets</td>
      <td>18</td>
    </tr>
    <tr>
      <td>Shoes</td>
      <td>Shoe shop</td>
      <td>13/09</td>
      <td>Big regrets</td>
      <td>65</td>
    </tr>
    <tr>
      <td>Toothpaste</td>
      <td>Supermarket</td>
      <td>13/09</td>
      <td>Good</td>
      <td>5</td>
    </tr>
  </tbody>
</table>

您可以在 GitHub 上找到完整的程式碼:spending-record-finished.html也可以檢視其現場執行情況)。

scope 屬性

scope 屬性可以新增到 <th> 元素中,以精確告訴螢幕閱讀器該標題是哪個單元格的標題——例如,它是其所在行的標題還是列的標題?回顧我們之前消費記錄的例子,您可以像這樣明確地將列標題定義為列標題

html
<thead>
  <tr>
    <th scope="col">Purchase</th>
    <th scope="col">Location</th>
    <th scope="col">Date</th>
    <th scope="col">Evaluation</th>
    <th scope="col">Cost (€)</th>
  </tr>
</thead>

並且每行都可以像這樣定義標題(如果我們同時新增行標題和列標題)

html
<tr>
  <th scope="row">Haircut</th>
  <td>Hairdresser</td>
  <td>12/09</td>
  <td>Great idea</td>
  <td>30</td>
</tr>

螢幕閱讀器將識別這種結構化的標記,並允許使用者一次性讀出整個列或行,例如。

scope 還有另外兩個可能的值——colgrouprowgroup。這些用於位於多個列或行之上的標題。如果您回顧本文開頭“2016 年 8 月銷售商品”表格,您會看到“服裝”單元格位於“褲子”、“裙子”和“連衣裙”單元格的上方。所有這些單元格都應標記為標題(<th>),但“服裝”是一個位於其上方並定義其他三個子標題的標題。“服裝”因此應獲得 scope="colgroup" 屬性,而其他標題將獲得 scope="col" 屬性

html
<thead>
  <tr>
    <th colspan="3" scope="colgroup">Clothes</th>
  </tr>
  <tr>
    <th scope="col">Trousers</th>
    <th scope="col">Skirts</th>
    <th scope="col">Dresses</th>
  </tr>
</thead>

同樣適用於多個分組行的標題。再次檢視“2016 年 8 月銷售的商品”表格,這次重點關注帶有“阿姆斯特丹”和“烏得勒支”標題(<th>)的行。您會注意到“荷蘭”標題(也標記為 <th> 元素)跨越了兩行,是另外兩個子標題的標題。因此,應在此標題單元格上指定 scope="rowgroup",以幫助螢幕閱讀器建立正確的關聯

html
<tr>
  <th rowspan="2" scope="rowgroup">The Netherlands</th>
  <th scope="row">Amsterdam</th>
  <td>89</td>
  <td>34</td>
  <td>69</td>
</tr>
<tr>
  <th scope="row">Utrecht</th>
  <td>80</td>
  <td>12</td>
  <td>43</td>
</tr>

idheaders 屬性

除了使用 scope 屬性之外,另一種方法是使用 idheaders 屬性來建立資料單元格和標題單元格之間的關聯。

<th> 元素可以為資料單元格 (<td>) 提供標題,在更復雜的表格中,還可以為另一個標題單元格 (<th>) 提供標題。這允許您建立分層或分組標題,其中一個標題描述了其他幾個標題。

headers 屬性用於將單元格(<td><th>)連結到一個或多個標題單元格。它接受一個以空格分隔的字串列表;字串的順序無關緊要。每個字串必須匹配與其關聯的 <th> 元素的唯一 id

這種方法為您的 HTML 表格提供了對每個單元格位置更明確的定義,基於它所屬的列和行的標題,有點像電子表格。為了使其良好工作,您的表格應該同時包含列標題和行標題。

讓我們看看“2016 年 8 月銷售商品”示例的一部分,以瞭解如何使用 idheaders 屬性

  1. 為表格中的每個 <th> 元素新增一個唯一的 id
  2. 對於標題單元格:為每個充當副標題的 <th> 元素新增一個 headers 屬性,即其上方還有另一個標題的標題單元格。該值是高級別標題的 id。在我們的示例中,列標題為 "clothes",行標題為 "belgium"
  3. 對於資料單元格:為每個 <td> 元素新增一個 headers 屬性,並將相關聯的 <th> 元素(一個或多個)的 id 作為以空格分隔的列表新增。您可以像在電子表格中那樣進行操作:找到資料單元格,然後找到描述它的行和列標題。指定的 id 順序無關緊要,但保持一致有助於保持程式碼的組織性和可讀性。
html
<thead>
  <tr>
    <th></th>
    <th></th>
    <th id="clothes" colspan="3">Clothes</th>
  </tr>
  <tr>
    <th></th>
    <th></th>
    <th id="trousers" headers="clothes">Trousers</th>
    <th id="skirts" headers="clothes">Skirts</th>
    <th id="dresses" headers="clothes">Dresses</th>
  </tr>
</thead>
<tbody>
  <tr>
    <th id="belgium" rowspan="2">Belgium</th>
    <th id="antwerp" headers="belgium">Antwerp</th>
    <td headers="belgium antwerp clothes trousers">56</td>
    <td headers="belgium antwerp clothes skirts">22</td>
    <td headers="belgium antwerp clothes dresses">43</td>
  </tr>
  <tr>
    <th id="ghent" headers="belgium">Ghent</th>
    <td headers="belgium ghent clothes trousers">41</td>
    <td headers="belgium ghent clothes skirts">17</td>
    <td headers="belgium ghent clothes dresses">35</td>
  </tr>
</tbody>

在此示例中

  • "Belgium"<th> 使用 rowspan="2" 跨越了 "Antwerp""Ghent"
  • 城市標題單元格("Antwerp""Ghent")使用 headers 屬性引用 "belgium" 以表明它們屬於比利時組。
  • 每個 <td> 都包含國家(belgium)、城市(antwerpghent)、組(clothes)和特定服裝專案(trousersskirtsdresses)的 headers 屬性。

注意:這種方法在標題和資料單元格之間建立了非常精確的關聯,但它使用了**大量**的標記,並且沒有留下任何出錯的空間。對於大多數表格來說,scope 方法通常就足夠了。

使用 scope 和 headers

在這個最後的練習中,我們將讓您嘗試在我們上面介紹的示例表上使用 scope 和 headers。

  1. 首先,在新目錄中,在本地複製 items-sold.htmlminimal-table.css
  2. 嘗試新增適當的 scope 屬性,以使此表格更易於訪問。
  3. 在另一個本地目錄中複製啟動檔案
  4. 這次透過使用 idheaders 屬性建立精確和明確的關聯,使表格更易於訪問。
點選此處顯示解決方案

第一個完成的 HTML 示例應該看起來像這樣

html
<table>
  <caption>
    Items Sold August 2016
  </caption>
  <thead>
    <tr>
      <td colspan="2" rowspan="2"></td>
      <th colspan="3" scope="colgroup">Clothes</th>
      <th colspan="2" scope="colgroup">Accessories</th>
    </tr>
    <tr>
      <th scope="col">Trousers</th>
      <th scope="col">Skirts</th>
      <th scope="col">Dresses</th>
      <th scope="col">Bracelets</th>
      <th scope="col">Rings</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th rowspan="3" scope="rowgroup">Belgium</th>
      <th scope="row">Antwerp</th>
      <td>56</td>
      <td>22</td>
      <td>43</td>
      <td>72</td>
      <td>23</td>
    </tr>
    <tr>
      <th scope="row">Ghent</th>
      <td>46</td>
      <td>18</td>
      <td>50</td>
      <td>61</td>
      <td>15</td>
    </tr>
    <tr>
      <th scope="row">Brussels</th>
      <td>51</td>
      <td>27</td>
      <td>38</td>
      <td>69</td>
      <td>28</td>
    </tr>
    <tr>
      <th rowspan="2" scope="rowgroup">The Netherlands</th>
      <th scope="row">Amsterdam</th>
      <td>89</td>
      <td>34</td>
      <td>69</td>
      <td>85</td>
      <td>38</td>
    </tr>
    <tr>
      <th scope="row">Utrecht</th>
      <td>80</td>
      <td>12</td>
      <td>43</td>
      <td>36</td>
      <td>19</td>
    </tr>
  </tbody>
</table>

而第二個應該看起來像這樣

html
<table>
  <caption>
    Items Sold August 2016
  </caption>
  <thead>
    <tr>
      <td colspan="2" rowspan="2"></td>
      <th colspan="3" id="clothes">Clothes</th>
      <th colspan="2" id="accessories">Accessories</th>
    </tr>
    <tr>
      <th id="trousers" headers="clothes">Trousers</th>
      <th id="skirts" headers="clothes">Skirts</th>
      <th id="dresses" headers="clothes">Dresses</th>
      <th id="bracelets" headers="accessories">Bracelets</th>
      <th id="rings" headers="accessories">Rings</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th rowspan="3" id="belgium">Belgium</th>
      <th id="antwerp" headers="belgium">Antwerp</th>
      <td headers="antwerp belgium clothes trousers">56</td>
      <td headers="antwerp belgium clothes skirts">22</td>
      <td headers="antwerp belgium clothes dresses">43</td>
      <td headers="antwerp belgium accessories bracelets">72</td>
      <td headers="antwerp belgium accessories rings">23</td>
    </tr>
    <tr>
      <th id="ghent" headers="belgium">Ghent</th>
      <td headers="ghent belgium clothes trousers">46</td>
      <td headers="ghent belgium clothes skirts">18</td>
      <td headers="ghent belgium clothes dresses">50</td>
      <td headers="ghent belgium accessories bracelets">61</td>
      <td headers="ghent belgium accessories rings">15</td>
    </tr>
    <tr>
      <th id="brussels" headers="belgium">Brussels</th>
      <td headers="brussels belgium clothes trousers">51</td>
      <td headers="brussels belgium clothes skirts">27</td>
      <td headers="brussels belgium clothes dresses">38</td>
      <td headers="brussels belgium accessories bracelets">69</td>
      <td headers="brussels belgium accessories rings">28</td>
    </tr>
    <tr>
      <th rowspan="2" id="netherlands">The Netherlands</th>
      <th id="amsterdam" headers="netherlands">Amsterdam</th>
      <td headers="amsterdam netherlands clothes trousers">89</td>
      <td headers="amsterdam netherlands clothes skirts">34</td>
      <td headers="amsterdam netherlands clothes dresses">69</td>
      <td headers="amsterdam netherlands accessories bracelets">85</td>
      <td headers="amsterdam netherlands accessories rings">38</td>
    </tr>
    <tr>
      <th id="utrecht" headers="netherlands">Utrecht</th>
      <td headers="utrecht netherlands clothes trousers">80</td>
      <td headers="utrecht netherlands clothes skirts">12</td>
      <td headers="utrecht netherlands clothes dresses">43</td>
      <td headers="utrecht netherlands accessories bracelets">36</td>
      <td headers="utrecht netherlands accessories rings">19</td>
    </tr>
  </tbody>
</table>

您還可以在 GitHub 上找到完整的示例

總結

關於 HTML 中的表格,您還可以學習其他一些知識,但目前您只需要瞭解這些。接下來,您可以嘗試我們的 HTML 表格挑戰。玩得開心!