<br> 拿來做間距
這是最普遍的 HTML 誤用,老專案裡幾乎都看得到。
<!-- ❌ 用 <br> 撐間距 -->
<p>第一段內容</p>
<br>
<br>
<p>第二段內容</p><br> 的語意是段落內的換行——詩句換行、地址換行、這類「換行本身有意義」的場合。它不是間距工具。
<!-- ✅ 間距是 CSS 的工作 -->
<p>第一段內容</p>
<p>第二段內容</p>p + p {
margin-top: 1.5rem;
}<br> 的確有合理用途:
<!-- ✅ 地址換行(換行本身有語意) -->
<address>
台北市信義區市府路 1 號<br>
台北市政府
</address>
<!-- ✅ 詩句換行 -->
<p>
春眠不覺曉,<br>
處處聞啼鳥。
</p><section> 當萬用容器
HTML5 推出之後有一波「全面語意化」的反應,結果很多人把每個 <div> 都換成 <section>。
<!-- ❌ section 沒有標題,純粹為了包 -->
<section class="hero-wrapper">
<img src="hero.jpg" alt="...">
</section>
<section class="flex-container">
<div>...</div>
<div>...</div>
</section><section> 的定義是「有主題的獨立段落,且有自己的標題(<h1>–<h6>)」。沒有標題的 section 等於告訴螢幕閱讀器「這是一個段落」但讀不出段落的主題——比 <div> 還糟,因為 <div> 至少不製造假語意。
判斷原則:
- 有標題且主題獨立 →
<section> - 純粹為了 CSS / JS 操作的容器 →
<div> - 可以獨立存在(拿去別頁也合理)→
<article>
<a> 沒有 href,或 href="#" 用來當按鈕
<!-- ❌ 沒有 href 的 <a> -->
<a onclick="openModal()">開啟說明</a>
<!-- ❌ href="#" 跳到頁頂,又不是真的連結 -->
<a href="#" onclick="doSomething(); return false;">執行動作</a><a> 的語意是導覽到另一個位置(URL、錨點、下載)。如果點了不會跳頁,它就不是連結,用 <button> 才對。
<!-- ✅ 觸發動作 → button -->
<button onclick="openModal()">開啟說明</button>
<!-- ✅ 真的要連到某處 → a with href -->
<a href="/docs/help">查看說明文件</a><a> 沒有 href 會讓鍵盤使用者無法聚焦(<a> 只有在有 href 時才預設可以 tab 到),螢幕閱讀器也不會把它識別為互動元素。
標題跳級——拿 <h3> 當「中字體」用
<!-- ❌ 為了字體大小跳過 h2 -->
<h1>文章標題</h1>
<p>...</p>
<h3>小節標題</h3> <!-- 跳過了 h2 -->
<h5>更小的字</h5> <!-- 跳過了 h4 -->標題標籤不是字體大小選項,是文件大綱。螢幕閱讀器使用者靠標題在頁面內快速跳轉,跳級等於大綱裡出現了洞。
如果你想要某個大小的標題字體,而那個層級語意上不對:
<!-- ✅ 語意正確,視覺大小用 CSS 調 -->
<h2 class="text-sm font-semibold">小節標題</h2>標題的語意層級和視覺大小完全可以分開控制。
<blockquote> 拿來做縮排
這個在舊專案和 CMS 產出的 HTML 裡很常見:
<!-- ❌ 不是引言,只是想要縮排 -->
<blockquote>
這段文字需要縮排一下看起來比較整齊。
</blockquote><blockquote> 的語意是引用另一個來源的內容。用它做縮排,螢幕閱讀器會告訴使用者「這是引言」,然後使用者等著看引用出處,結果什麼都沒有。
<!-- ✅ 縮排是 CSS 的工作 -->
<p class="indented">這段文字需要縮排。</p>
<!-- ✅ 真正的引言用法 -->
<blockquote cite="https://example.com/source">
<p>任何傻瓜都能寫出電腦能看懂的程式。</p>
<footer>— <cite>Martin Fowler</cite></footer>
</blockquote><b> 和 <strong> 用反了
semantic.md 有完整的差異說明,這裡只說最常見的誤用場景:
<!-- ❌ 想表達「這很重要!」卻用 <b> -->
<p>請注意:<b>密碼不能少於 8 個字元</b></p>
<!-- ❌ 只是想要粗體視覺效果,卻用 <strong> -->
<strong>品牌名稱</strong> <!-- 不是重要性,是視覺標記 --><!-- ✅ 重要性警告 → <strong> -->
<p>請注意:<strong>密碼不能少於 8 個字元</strong></p>
<!-- ✅ 純視覺粗體(產品名、關鍵字)→ <b> -->
<b>品牌名稱</b>
<!-- ✅ 只是想要粗體外觀,沒有語意 → CSS -->
<span class="font-bold">標題文字</span>螢幕閱讀器有些實作會對 <strong> 加強語氣朗讀,<b> 則不會。把它們用反,傳遞的語意就錯了。
<p> 裡面放塊狀元素(invalid HTML)
這個瀏覽器會靜默修復,所以很多人不知道這是錯的:
<!-- ❌ <p> 裡面不能放 block-level element -->
<p>
這是一段說明
<div class="tip">補充資訊</div>
繼續說明
</p><p> 是 inline 容器,遇到 <div>、<h2>、<ul> 等塊狀元素時,瀏覽器會自動把 <p> 截斷。結果是:HTML 你寫了一個 <p>,DOM 裡變成兩個。這種靜默修復會讓 CSS 和 JS 行為難以預測。
<!-- ✅ 用 <div> 包或改用 <span> -->
<div class="paragraph-with-tip">
<p>這是一段說明</p>
<div class="tip">補充資訊</div>
<p>繼續說明</p>
</div>用 W3C Validator 或 HTMLHint 就能抓到這類 invalid nesting,建議 CI 加進去。
相關文章
- HTML 語意化標籤:結構六大標籤與判斷方法 —
<b>/<strong>/<i>/<em>完整差異、<section>vs<div>決策樹 - 為什麼不能只用 div — 語意化的根本理由
- HTML Anti-patterns — 結構層面的地雷(濫用 div、重複 id、tabindex 誤用)