為什麼 HTML 的問題最難發現
JavaScript 錯了會噴 console error;CSS 錯了畫面明顯壞掉。HTML 的問題通常靜默發生——頁面看起來正常,但螢幕閱讀器失效、爬蟲抓錯、CSS 選擇器衝突,問題要到很後期才浮現。
Anti-pattern 1:div 濫用——每個東西都包一層
<!-- ❌ 不必要的 div 包裝 -->
<div class="title-wrapper">
<div class="title-inner">
<h1>頁面標題</h1>
</div>
</div>
<!-- ✅ 標題就是標題 -->
<h1>頁面標題</h1>每多一層 div,CSS 選擇器就多一層、DOM 就多一個節點、JavaScript 遍歷就多一步。遇到需要包裝的情況先問:這個 wrapper 是語意需要,還是 CSS 習慣?
如果只是為了讓 flexbox 生效,很多時候直接在父元素加 CSS 就解了。
Anti-pattern 2:重複 id
<!-- ❌ id 在整個頁面必須唯一 -->
<div id="card">商品 A</div>
<div id="card">商品 B</div>
<div id="card">商品 C</div>id 的定義是頁面唯一識別符。重複 id 的後果:
document.getElementById('card')只回傳第一個- CSS
#card選擇器理論上只應該命中一個,但瀏覽器行為不一致 <label for="...">和aria-labelledby="..."指向重複 id 會失效- W3C Validator 會報錯,部分爬蟲會困惑
動態產生的卡片、列表項目改用 class,或加 index(id="card-1"、id="card-2")。
Anti-pattern 3:不必要的巢狀
<!-- ❌ inline 元素包 block 元素(invalid HTML) -->
<span>
<div>這個 div 在 span 裡</div>
</span>
<!-- ❌ p 包 div(invalid HTML,瀏覽器會自動截斷 p) -->
<p>
說明文字
<div class="note">補充</div>
繼續說明
</p>
<!-- ❌ a 包 a(invalid HTML) -->
<a href="/outer">
外層連結
<a href="/inner">內層連結</a> <!-- 瀏覽器會截斷 -->
</a>這些 invalid 巢狀不會報錯,但瀏覽器的自動修復行為不一致,會造成奇怪的 CSS / JS bug。用 W3C Validator 跑一遍就能抓到。
Anti-pattern 4:tabindex 正數
<!-- ❌ 用正數 tabindex 強制改 tab 順序 -->
<input tabindex="3" name="last-name">
<input tabindex="1" name="first-name">
<button tabindex="2">送出</button>正數 tabindex 會打亂鍵盤使用者和螢幕閱讀器的預期流程,維護時改了 HTML 順序還要同步改 tabindex 數字,很快變成地雷。
正確做法:讓 DOM 順序就是正確的 tab 順序。需要用到的只有:
tabindex="0":讓非互動元素加入 tab 順序(自訂元件時)tabindex="-1":讓元素可以.focus()但不在 tab 順序裡(modal 聚焦管理)
Anti-pattern 5:onclick 加在非互動元素
<!-- ❌ div / span 綁 click 事件,鍵盤用不了 -->
<div onclick="doSomething()">點我執行</div>
<span onclick="openMenu()">選單</span>
<!-- ✅ 用 button,天生可以 tab、Enter/Space 觸發 -->
<button onclick="doSomething()">點我執行</button>
<button onclick="openMenu()">選單</button><div> 的 click 事件滑鼠可以觸發,但鍵盤使用者 tab 不到(<div> 預設不可聚焦),Enter 也不會觸發。如果一定要用 div,要補 tabindex="0" 加 keydown 監聽 Enter 和 Space——工作量是用 <button> 的五倍,還不如一開始就用對元素。
Anti-pattern 6:alt 屬性誤用
<!-- ❌ 資訊圖片沒有 alt -->
<img src="revenue-chart.png">
<!-- ❌ 裝飾圖片有不必要的 alt,螢幕閱讀器會朗讀 -->
<img src="divider.svg" alt="分隔線裝飾">
<!-- ❌ alt 直接填檔名 -->
<img src="IMG_0042.jpg" alt="IMG_0042">
<!-- ✅ 資訊圖片:描述圖片傳達的資訊 -->
<img src="revenue-chart.png" alt="2026 Q1 營收較去年同期成長 23%">
<!-- ✅ 裝飾圖片:alt="" 讓螢幕閱讀器完全跳過 -->
<img src="divider.svg" alt="">
<!-- ✅ 圖示按鈕:描述功能,不是圖示外觀 -->
<button><img src="search-icon.svg" alt="搜尋"></button>alt 的原則:如果圖片消失,使用者需要知道什麼才不會失去資訊? 那就是 alt 要寫的內容。裝飾圖片消失使用者不需要知道任何事,所以 alt=""。
快速工具清單
| 問題 | 工具 |
|---|---|
| invalid HTML、重複 id、非法巢狀 | W3C Validator |
| alt 缺失、ARIA 問題、tab order | axe DevTools(Chrome 擴充套件) |
| 全面 a11y 稽核 | Chrome DevTools → Lighthouse → Accessibility |
| 程式碼靜態分析 | HTMLHint(可加進 CI) |
工具細節見 HTML 檢查工具。
相關文章
- 最常被誤用的 HTML 標籤 — 標籤層面的誤用(
<br>排版、<section>當萬用容器) - ARIA 和原生語意 — tabindex / onclick 的正確替代方案