# 前提: 紀錄 table 標籤的正式規範 ### **✔ 正式規範(HTML Standard)** #### **一個 `<table>` 可以由以下任意組合構成:** ``` * <table>:表格本體(必須) * <thead>:表頭區(可選) * <tbody>:內容區(可選)-(若沒填寫時, 瀏覽器也會自動補) * <tfoot>:表尾區(可選) * <tr>:行(row)(必須) * <th>:表頭欄位(header cell)(必須) * <td>:一般欄位(data cell)(必須) * <caption> * <colgroup> ``` 其中: ##### 👉 `<thead>、<tbody>、<tfoot>` 都是可選的 ##### 👉 表格最少只需要 `<table><tr><td></td></tr></table>` 就能成立 --- ### **✔ 那什麼時候需要`<thead>`?** ##### 👉建議加 `<thead>` 的情況: * 有明確「表頭列」 * 想增加語意化(semantic) * 想提升可及性(a11y) * 想要更好的結構、維護性 * 需要固定表頭(sticky header) * 要用 CSS 做 table layout 時更好控制 -- **例如:** ``` html. <table> <thead> <tr> <th>商品</th> <th>數量</th> <th>金額</th> </tr> </thead> <tbody> <tr> <td>Apple</td> <td>3</td> <td>300</td> </tr> </tbody> </table> ``` --- ### **✔ 那什麼時候不需要 `<thead>`?** **你也可以完全不寫:** ``` html. <table> <tr> <th>商品</th> <th>數量</th> <th>金額</th> </tr> <tr> <td>Apple</td> <td>3</td> <td>300</td> </tr> </table> ``` 仍然合法。 --- ### **✔ Bootstrap 需要 `<thead>` 嗎?** Bootstrap 的 .table 語法: * 不強制 `<thead>` * 但 Bootstrap 的 table 樣式有針對 `<thead>` 做優化(字體、背景等) **如果你不寫 `<thead>`,樣式也不會壞,只是少了表頭樣式。** --- ### **📌 正確觀念** **一個最簡單、合法的 HTML table 只需要這樣:** ``` html. <table> <tr> <td>資料</td> </tr> </table> ``` 這是完全合法的 HTML。 --- ### **❗ 那為什麼大家常加 `<tbody>` 和 `<thead>`?** 雖然不是必須,但以下情況強烈建議使用: -- #### **⭐ 使用 `<thead>` 的理由** * 語意化更清楚(表頭在哪一行) * 螢幕閱讀器可理解欄位名稱 * CSS sticky header 很好做(position: sticky) * 排序 plugin(DataTables, bootstrap-table)可正確辨識表頭 -- #### **⭐ 使用 `<tbody>` 的理由** * 讓瀏覽器能建立更完整的 table model * 多個 `<tbody>` 可以分區資料(不常用但合法) * **操作 JS 時容易選取表身資料,例如:** ``` document.querySelector("tbody") ``` **若沒有 tbody,有些瀏覽器會自動補上,但你不一定能精準控制。** -- #### **⭐ 使用 `<tfoot>` 的理由** * 固定顯示總計、結尾欄位 * 在印表模式中會固定在每頁底部(很有用) * CSS 可針對表尾做排版 --- ## **🎯 最佳實務(如果你是做後台、管理頁)** ``` html. <table> <thead> <tr> <th>欄位1</th> <th>欄位2</th> </tr> </thead> <tbody> <tr> <td>資料1</td> <td>資料2</td> </tr> </tbody> <tfoot> <tr> <td colspan="2">總計</td> </tr> </tfoot> </table> ``` --- # 🔍 接著介紹一下 `<tr>` 的基本功能: #### **🎯 `<tr>` 是什麼?** `<tr>` = Table Row(表格的一列) * 它是` <table> → <thead>/<tbody>/<tfoot> → <tr> → <th>/<td>`中間的「列」容器。 -- #### **🧩 1. `<tr>` 的合法父層(只能放在這些裡面)** 根據 HTML 規範: `<tr>` 只能放在: ``` * <thead> * <tbody> * <tfoot> * <table>(特殊情況下) ``` 不合法的例子(會被瀏覽器修復錯位): ``` <div> <tr> ❌ 錯誤 ``` -- #### **🧩 2. `<tr>` 裡面能放什麼?** 只能放: ``` <th> <td> ``` 還有少數例外(rare): ``` <script> <template> ``` 不能放: ``` <div> <span> <p> ``` **瀏覽器會強制修正,自動移到外面。** -- #### **🧩 3. `<tr>` 的預設顯示(重要)** **預設:** ``` display: table-row; ``` ### **⚠ 很重要的規則:** 你可以改成: * block(不推薦) * flex(不推薦) * display: none(可用) * grid(可用但不建議) * inline(不建議) 你不能改成: * table-header-group * table-row-group * table-column * table-cell **因為這會破壞 table model。** --- #### **🧩 4. `<tr>` 現代常用語意(ARIA)** **雖然 `<tr>` 沒有太多自帶功能,但可加入 ARIA:** | 屬性 | 用途 | | ---------------------- | --------------- | | `role="row"` | 明確標示「這是列」 | | `aria-selected="true"` | 表示該列被選取(例如點選列表) | | `aria-expanded="true"` | 展開/收起的列 | | `aria-label` | 描述該列內容 | --- # 🔍 接著介紹一下 `<th>` 跟 `<td>` 的基本功能以及可用的所有屬性: #### **🧩 1. `<th>` 的 scope — 表頭作用範圍(非常重要)** **`scope` 是 `<th>` 專屬的屬性,用來描述:** * ### **這個表頭(header)控制哪一個方向的資料(cells)。** 在可及性(A11y)與複雜表格中非常重要,也能提升 SEO。 -- **✔ `scope="col"`(最常用)** 表頭控制 **整欄(column)**。 ``` <th scope="col">價格</th> ``` 📌 用途:表格第一列欄位名稱 -- **✔ `scope="row"`** 表頭控制 **整列(row)**。 ``` <tr> <th scope="row">商品 A</th> <td>30</td> <td>5</td> </tr> ``` -- **✔ `scope="colgroup"`** 控制**一整組欄(由 `<colgroup>` 划分)**。 ``` <th scope="colgroup">2025 年</th> ``` 通常用於跨欄表頭。 -- **✔ `scope="rowgroup"`** 控制**一整組列**。 ``` <th scope="rowgroup">水果類</th> ``` ### **🎯 scope 的結論** | scope | 控制方向 | | ---------- | ----- | | `col` | 向下作用 | | `row` | 向右作用 | | `colgroup` | 控制整組欄 | | `rowgroup` | 控制整組列 | ### **✔ 最常用的是 `col、row`。** --- #### **🧩 2. `<th> / <td>` 的 colspan(跨欄位)** 讓 cell 橫向跨越多欄。 ``` <th colspan="5">預約紀錄一覽</th> ``` 注意: ##### * 只能用在 `<th>` 和 `<td>` ##### * `colspan` 的數字必須 ≤ (小於或等於) 該 "`<tr>`" 的欄數 ##### * `colspan` 是橫向合併 --- #### **🧩 3. `<th> / <td>` 的 rowspan(跨列)** 讓 cell 縱向跨越多列。 ``` <td rowspan="3">統一編號</td> ``` ##### * 用於左側欄位合併常見 ##### * 與 `colspan` 可同時使用 --- #### **🧩 4. `<th>` 的其他隱藏屬性(少見但很重要)** **✔ `abbr`** 給表頭提供簡短縮寫(供螢幕閱讀器或窄螢幕使用)。 ``` <th abbr="Qty">數量</th> ``` -- **✔ `headers`** 指定 `<td>` 所屬的 `<th>`,在複雜表格使用。 ``` <th id="price">價格</th> <td headers="price">300</td> ``` 用途: **讓複雜跨行跨列的表格也能保持可及性** --- #### **🧩 5. `<td>` 可用的全部屬性(你問的「隱藏屬性」)** 其實 `<td>` 的內建屬性不多,但能做的事比你想像多。 -- **✔ `colspan`(橫向合併)** ``` <td colspan="3">合併 3 欄</td> ``` -- **✔ `rowspan`(縱向合併)** ``` <td rowspan="2">合併 2 列</td> ``` -- **✔ `headers`** 與 `<th id="">` 搭配,用於複雜表格。 ``` <td headers="product price">100 元</td> ``` --- #### **🧩 6. `<td>` 的 ARIA 隱藏屬性(可選但實務很常用)** 這部分很少人知道,但對無障礙、動態表格非常重要。 -- **✔ `role="cell"`(標準 cell)** 通常不用自己加,瀏覽器會自動設定。 -- **✔ `aria-label`** 給 cell 一個可讀名稱(手機版表格常用)。 ``` <td aria-label="價格">300</td> ``` -- #### **✔ `aria-labelledby`** 指向文字來源。 ``` <td aria-labelledby="price-label">300</td> ``` -- #### **✔ `aria-sort`** 如果你做 sortable table,可以給表頭用。 ``` <th aria-sort="ascending">價格</th> ``` **可用值:** * `"none"` * `"ascending"` * `"descending"` * `"other"` --- #### **🧩 7. `<td>` 也能使用 data-*(非常常用)** 例如做手機版卡片表格: ``` html. <td data-title="價格">300</td> ``` 然後 CSS 顯示: ``` css. td::before { content: attr(data-title) ": "; } ``` --- ## 🎉 最終總整理(讓你完全記住) ✅ HTML 規範:哪些 table 元素是必須的? | 元素 | 用途 | 常見嗎? | 必要嗎? | | ------------ | ------- | ---- | ------------- | | `<caption>` | 表格標題 | 中 | ❌ | | `<colgroup>` | 欄位設定 | 低 | ❌ | | `<thead>` | 表頭 | 高 | ❌(但強烈建議) | | `<tbody>` | 表身 | 高 | ❌(瀏覽器會自動加) | | `<tfoot>` | 表尾 | 中 | ❌ | | `<tr>` | 資料列 | 必備 | ✔ | | `<th>` | 表頭 cell | 高 | ❌(資料列不一定要 th) | | `<td>` | 資料 cell | 必備 | ✔ | -- ## 🎯 完整總結 `<tr>` 你該知道的所有事 **✔ `<tr>` 的用途:** * 表格的一列(row) **✔ `<tr>` 的合法結構:** * 只能包含 `<th> / <td>` * 只能放在 `<thead> / <tbody> / <tfoot>` **✔ `<tr>` 的 display:** * 預設:`table-row` * 可改成 none(隱藏) * 可改成 block(做 RWD table) * ❌ 不能改成 `table-header-group` 等 **✔ `<tr>` 常用的現代屬性:** ##### * aria-selected ##### * aria-expanded ##### * role="row" ✔ `<tr>` 做 RWD 的最佳用法: ``` <tr class="d-none d-lg-table-row"> ``` -- ## 🎯 完整總結`<th>` 有的屬性(最完整) | 屬性 | 用途 | | ----------------- | --------------------------------------- | | `scope` | 指定表頭方向(col / row / colgroup / rowgroup) | | `colspan` | 合併欄 | | `rowspan` | 合併列 | | `abbr` | 表頭簡寫 | | `headers` | 指定 id 參照,用於複雜表格 | | `aria-sort` | 排序狀態用 | | `aria-label` | 語意文字 | | `aria-labelledby` | 語意引用 | -- ## 🎯 完整總結`<td>` 有的屬性(最完整) | 屬性 | 用途 | | ---------------------------------- | --------------- | | `colspan` | 合併欄 | | `rowspan` | 合併列 | | `headers` | 指向 `<th id="">` | | `data-*` | RWD 表格常用 | | ARIA(aria-label / aria-labelledby) | 無障礙提升 | -- ## 🎯 在 table 中: 各個標籤的預設 display | 元素 | 預設 display | | --------------- | ------------------ | | `<thead>` | table-header-group | | `<tbody>` | table-row-group | | `<tfoot>` | table-footer-group | | `<tr>` | table-row | | `<th>` / `<td>` | table-cell | --- ## ⭐ 建議最佳實務(前端工程師版本) **✔ 1. 永遠加 `<thead>` 與 `<tbody>`** 理由: * 排序外掛正常 * sticky header 容易做 * 可及性(A11y)更好 * 結構清楚 **✔ 2. 表頭一定要用 `<th scope="col">`** * 提升語意 * 有利於 SEO * 有利於讀屏工具正確朗讀 **✔ 3. 一律避免改 `<th> / <td>` 的 display(除非必要)** 否則: * colspan 會壞 * row height 會變怪 * alignment 無法預測 **✔ 4. `<tfoot>` 放不放可視需求** * 印表時非常有用。