紀錄工作經驗、相關知識,解決技術相關問題。

HTML, 新手 Jamp Holes

多重 header 怎麼用?HTML5 區段內容與頁首標籤的巢狀階層拆解

多重 header 怎麼用?HTML5 區段內容與頁首標籤的巢狀階層拆解 特色圖片

💡 文章重點摘要:在前端面試與團隊 Code Review 中,最常出現的爭論莫過於:「一個 HTML 頁面裡到底能不能出現多個 <header>?」有人堅持全頁只能有一個頁首,也有人在每個卡片與章節都放 <header> 卻擔心會讓螢幕閱讀器抓狂。本文將依據 WHATWG HTML Living Standard 與 W3C HTML-AAM 1.0 官方規範,帶你徹底搞懂 多重 header 的上下文角色自動降級機制,並破除早已被廢除的「HTML5 Document Outline 大綱演算法」歷史迷思!

在上一篇《HTML5 header 內只能放標題嗎?剖析導覽列、搜尋框與巢狀結構的最佳實踐》中,我們拆解了單一 <header> 內部該如何擺放 Logo、<nav> 與 <search>。但當網頁規模擴大——同時包含「全站頂部導覽」、「主文章標頭」、「文章內的子章節導讀」以及「留言區每則讀者評論的標頭」時,我們就會面臨 多重 header 的架構設計問題。

究竟同一個頁面寫 4、5 個 <header> 合不合法?為什麼頂層 <header> 是全站地標,放進 <article> 裡就不是?各層 <header> 裡面的 <h1>、<h2>、<h3> 又該如何分配才不會搶走 SEO 權重?接下來我們直接從 30 秒即用範本與底層映射規則開始剖析!


⚡ 快速簡單使用(30 秒複製即用範本)

在同一份 HTML 文件中,你可以合法使用多個 <header>,只要確保**「全站頂層(<body> 直接子代)只有 1 個 <header>,其餘 <header> 皆包裹在 <article>、<section> 或 <aside> 等區段容器內」**。請直接複製以下標準四層架構範本:

<!DOCTYPE html>
<html lang="zh-Hant-TW">
<head>
  <meta charset="UTF-8">
  <title>HTML5 多重 header 標準巢狀架構範本</title>
</head>
<body>
  <!-- 1️⃣ 第 1 個 <header>(位於 <body> 頂層):W3C 自動映射為全站唯一 role="banner" 橫幅地標 -->
  <header class="site-header">
    <a href="/" class="brand-logo">Sean 的技術筆記</a>
    <nav aria-label="主導覽選單">
      <ul>
        <li><a href="/html" aria-current="page">HTML 專欄</a></li>
        <li><a href="/seo">SEO 指南</a></li>
      </ul>
    </nav>
  </header>

  <main>
    <article class="post-article">
      <!-- 2️⃣ 第 2 個 <header>(位於 <article> 內):自動降級為 role="generic",放全頁唯一 <h1> -->
      <header class="article-header">
        <h1>多重 header 怎麼用?HTML5 區段內容與頁首標籤的巢狀階層拆解</h1>
        <p>作者:Sean · 發布於 <time datetime="2026-10-24">2026-10-24</time></p>
      </header>

      <!-- 3️⃣ 第 3 個 <header>(位於 <section> 內):自動降級為 role="generic",放章節 <h2> 與導讀 -->
      <section class="chapter-section" aria-labelledby="ch1-title">
        <header class="section-header">
          <h2 id="ch1-title">一、 區段內容與多重頁首的底層映射關係</h2>
          <p class="chapter-lead">本節將解析 W3C 無障礙樹如何根據父容器動態切換 header 的角色。</p>
        </header>
        <p>這裡是第一章節的正文段落...</p>
      </section>
    </article>
  </main>

  <!-- 4️⃣ 第 4 個 <header>(位於 <aside> 內):自動降級為 role="generic",放側欄區塊 <h2> -->
  <aside class="sidebar" aria-labelledby="hot-posts-title">
    <header class="widget-header">
      <h2 id="hot-posts-title">本週熱門技術文章</h2>
    </header>
    <ul>
      <li><a href="/html/html-header-vs-head-semantic-pitfalls/">head 與 header 的致命混淆</a></li>
    </ul>
  </aside>
</body>
</html>

一、 5 秒快速索引:多重 header 在不同父容器下的語意與角色速查表

許多工程師擔心:「如果一個頁面寫了 5 個 <header>,視障朋友的螢幕閱讀器會不會播報 5 個全站橫幅(Banner Landmark),害他們迷路?」
答案是:只要放對父容器,完全不會! 根據 W3C HTML Accessibility API Mappings 1.0 (HTML-AAM) 規範,瀏覽器會根據 <header> 的祖先元素自動切換其無障礙角色:

<header> 的所在位置(DOM 階層)所屬語意定位W3C 無障礙樹角色 (ARIA Role)內部推薦標題層級(單篇內頁)是否允許巢狀?
<body> > <header>(無區段內容與 <main> 祖先)全站頂層頁首 (Global Site Header)🟢 role="banner"(全頁唯一橫幅地標)不放 <h1>(Logo 用 <a> 包裹,把 <h1> 留給文章)✅ 合法(全頁限 1 個頂層 banner)
<article> > <header>獨立文章標頭 (Article Header)🔵 role="generic"(一般群組,非地標)全頁唯一 <h1>(單篇內頁)或 <h2>(列表卡片頁)✅ 合法(隨 <article> 數量配置)
<section> > <header>主題章節標頭 (Section Header)🔵 role="generic"(一般群組,非地標)<h2> 或 <h3>(搭配章節前言或統計摘要)✅ 合法(當章節除了標題還有導讀時使用)
<aside> > <header>側欄模組標頭 (Sidebar Widget Header)🔵 role="generic"(一般群組,非地標)<h2> 或 <h3>(側邊欄小工具標題)✅ 合法
<footer> > <header> 或 <header> > <header>非法結構 (Syntax Error)🔴 W3C 驗證器直接報錯禁用❌ 嚴格禁止(違反 WHATWG 內容模型)

二、 深入底層:為什麼同一個頁面可以有多個 header 卻不會地標氾濫?

在 HTML4 時代,開發者只能用 <div id="header"> 建立全站唯一的頂部區塊。進入 HTML5 後,規範引入了 Sectioning Content(區段內容:<article>、<section>、<aside>、<nav>) 的概念(詳見《HTML 語意化標籤的邊界:談 section、article 與 aside 的巢狀邏輯陷阱》)。

請透過下圖觀察瀏覽器引擎在建構無障礙樹(Accessibility Tree)時,是如何聰明地為 多重 header 執行「上下文自動降級(Contextual Role Demotion)」:

圖 1:單一網頁中多重 header 的 W3C HTML-AAM 無障礙角色映射與自動降級機制圖
圖 1:單一網頁中多重 header 的 W3C HTML-AAM 無障礙角色映射與自動降級機制圖

1. W3C HTML-AAM 的「祖先攔截規則」

根據 W3C HTML-AAM 1.0 §3.4 (header element) 官方定義:

  • 唯有當 <header> 不是 <article>、<aside>、<main>、<nav> 或 <section> 的後代時,瀏覽器才會將它映射為 role="banner" 地標。
  • 一旦 <header> 被包裹在上述任何一個區段元素或 <main> 裡面,瀏覽器就會自動解除它的地標身分,改映射為 role="generic"!
    這項精妙的設計,確保了螢幕閱讀器使用者按下地標快捷鍵時,只會精準跳到全站最上方的唯一頂層 <header>,而不會被文章內部或章節內部的局部 <header> 干擾。

2. ⚠️ 破除歷史迷思:別再相信早已被廢除的「HTML5 Document Outline 大綱演算法」!

許多舊教材或老文章在解釋 多重 header 時,會宣稱:「因為 <article> 與 <section> 會建立獨立的 Document Outline(文件大綱作用域),所以裡面的每個 <header> 都可以各自寫一個 <h1>!」

請立刻把這個過時觀念從腦中刪除!
事實上,當年 W3C / WHATWG 雖然曾提出過 Document Outline 演算法草案,但全球沒有任何一款主流瀏覽器(Chrome、Safari、Firefox)或螢幕閱讀器(NVDA、JAWS、VoiceOver)真正實作過這套演算法。因此,WHATWG 已於 2022 年正式從 HTML 標準規格書中徹底移除 Document Outline 演算法!

在 2026 年的現代網頁開發中,無論你的 <header> 包在幾層 <article> 或 <section> 裡面,整張網頁的標題階層永遠是全域計算的(全頁依然只應有 1 個主 <h1>,接著依序使用 <h2> ➔ <h3>)!


三、 標題層級(h1 / h2 / h3)在多重 header 中的黃金分配法則

既然不能在每個 <header> 都亂塞 <h1>,那麼當頁面同時存在多個 <header> 時,裡面的標題標籤該怎麼配?這取決於你的頁面屬於「單篇文章內頁」還是「文章列表/分類頁」:

圖 2:多重 header 內的標題層級(h1 / h2 / h3)配置決策樹 — 單篇內頁 vs. 列表卡片頁
圖 2:多重 header 內的標題層級(h1 / h2 / h3)配置決策樹 — 單篇內頁 vs. 列表卡片頁

情境 A:單篇文章內頁(Single Post Detail Page)

許多舊版部落格最大的 SEO 敗筆,就是在頂層 <header class="site-header"> 把網站名稱寫成 <h1>Sean 的技術筆記</h1>,然後把真正重要的文章標題 <article><header><h2>...</h2></header> 降級成 <h2>!這會導致全站幾百篇文章的 <h1> 通通長一樣,嚴重稀釋單篇文章的關鍵字權重。

  • 正確分配:
    1. <body> > <header class="site-header">:網站名稱與 Logo 使用 <a href="/">(不包 <h1>)。
    2. <main> > <article> > <header class="post-header">:放置**全頁唯一的 <h1>(文章主標題)**與發布時間 <time>。
    3. <article> > <section> > <header class="section-header">:放置章節標題 <h2> 與章節導言。
    4. 留言區 <section> > <article class="comment"> > <header>:放置單則留言標題或留言者名稱 <h3>。

情境 B:分類歸檔/文章卡片列表頁(Category / Archive Feed Page)

當頁面是顯示 10 篇文章預覽卡片的「HTML5 專欄列表頁」時,頁面有 10 個 <article class="post-card">,每個卡片都有自己的 <header>:

  • 正確分配:
    1. <body> > <header class="site-header">:網站 Logo 使用 <a href="/">。
    2. <main> > <header class="archive-header">:放置**全頁唯一的 <h1>(例如:<h1>HTML5 語意化實戰專欄</h1>)**與專欄介紹。
    3. 底下 10 張 <article class="post-card"> > <header>:每張卡片的文章標題統一使用 <h2><a href="...">文章標題</a></h2>!

四、 生產級實戰對決:從「大綱破版反模式」重構為「滿分多重 header 架構」

接下來我們透過完整的可執行代碼,對比「把 <h1> 給網站 Logo 且濫用 <header>」的錯誤寫法,與符合 WHATWG / W3C HTML-AAM 標準的生產級多重 <header> 架構。

1. ❌ 常見翻車反模式(全站 Logo 搶走 h1 + 在 footer 內塞 header)

<body>
  <!-- ❌ 陷阱 1:把全頁唯一 <h1> 給了全站共用的網站名稱,害文章主標題被迫降為 <h2>! -->
  <header class="site-header">
    <h1>Sean 的技術筆記</h1>
  </header>

  <main>
    <!-- ❌ 陷阱 2:直接在 <main> 底下寫第 2 個沒有被 <article>/<section> 包裹的裸露 <header>,易造成結構混淆 -->
    <header class="announcement">全站系統維護公告</header>

    <article>
      <header>
        <!-- ❌ 陷阱 3:真正的文章主標題卻被降級成 <h2>,傷害單文 SEO 主題權重 -->
        <h2>多重 header 巢狀階層完整教學</h2>
      </header>

      <section>
        <!-- ❌ 陷阱 4:如果章節只有單純一行 <h3> 標題、沒有任何副標或導言,多包一層 <header> 屬於多餘冗贅 -->
        <header>
          <h3>什麼時候需要章節 header?</h3>
        </header>
        <p>內文段落...</p>
      </section>
    </article>
  </main>

  <footer>
    <!-- ❌ 陷阱 5:在 <footer> 裡面塞 <header>,直接違反 WHATWG 語法規範(HTML Validator 報錯)! -->
    <header>
      <h4>聯絡我們</h4>
    </header>
    <p>[email protected]</p>
  </footer>
</body>

2. 🟢 生產級標準重構範例(含四層多重 header 與無障礙角色自動化驗證腳本)

<!DOCTYPE html>
<html lang="zh-Hant-TW">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>多重 header 怎麼用?HTML5 巢狀階層標準範例</title>
</head>
<body>
  <!-- ✅ 第 1 層:全站頂層 <header> (唯一 role="banner" 地標) -->
  <header class="site-header">
    <a href="/" class="site-brand">Sean 的技術筆記</a>
    <nav aria-label="主要選單">
      <ul>
        <li><a href="/html" aria-current="page">HTML 專欄</a></li>
        <li><a href="/web-perf">效能調優</a></li>
      </ul>
    </nav>
  </header>

  <main>
    <article class="main-article">
      <!-- ✅ 第 2 層:主文章 <header> (位於 <article> 內 -> role="generic",擁有全頁唯一 <h1>) -->
      <header class="article-header">
        <hgroup>
          <p class="category-badge">HTML5 架構實戰</p>
          <h1>多重 header 怎麼用?HTML5 區段內容與頁首標籤的巢狀階層拆解</h1>
        </hgroup>
        <div class="post-meta">
          <span>作者:Sean</span> · 
          <time datetime="2026-10-24">2026 年 10 月 24 日</time> · 
          <span>閱讀時間:6 分鐘</span>
        </div>
      </header>

      <!-- ✅ 第 3 層:章節 <header> (當章節包含 <h2> + 導讀摘要/數據指標時,使用 <header> 群組化) -->
      <section class="article-section" aria-labelledby="sec-architecture">
        <header class="section-header">
          <h2 id="sec-architecture">一、 企業級內容網站的多重標頭拓撲</h2>
          <p class="section-summary">核心指標:全頁限 1 個頂層 banner 地標、1 個主標題 H1,其餘區段標頭自動降級為 generic。</p>
        </header>
        <p>當章節開頭除了標題之外,還附帶章節引言、最後更新時間或操作按鈕時,使用 <code>&lt;section&gt; &gt; &lt;header&gt;</code> 就能將這組標頭資訊與下方正文段落清楚切分。</p>
      </section>

      <!-- ✅ 第 4 層:讀者留言區(巢狀 <article> 內的局部 <header>) -->
      <section class="comments-section" aria-labelledby="sec-comments">
        <h2 id="sec-comments">二、 讀者技術交流(共 1 則留言)</h2>

        <article class="comment-item">
          <header class="comment-header">
            <h3>前端工程師 Leo</h3>
            <p>留言於 <time datetime="2026-10-24T14:20:00+08:00">2026-10-24 14:20</time></p>
          </header>
          <p>原來以前學的 Document Outline 演算法已經在 2022 年被廢除了,把 H1 留給文章標題真的清楚多了!</p>
        </article>
      </section>
    </article>
  </main>

  <footer class="site-footer">
    <!-- ✅ 頁尾區塊直接使用標題或段落,絕不在 <footer> 內嵌套 <header> -->
    <h2>關於本站</h2>
    <p>&copy; 2026 seanacnet.com All Rights Reserved.</p>
  </footer>

  <script>
    // 🔍 生產環境自檢腳本:盤點全頁所有 <header> 的上下文角色與標題層級
    function auditMultipleHeaders() {
      const allHeaders = Array.from(document.querySelectorAll('header'));
      const report = allHeaders.map((hdr, index) => {
        const isScoped = hdr.closest('article, aside, main, nav, section') !== null;
        const computedRole = isScoped ? 'generic (區段局部標頭)' : 'banner (全站頂層地標)';
        const heading = hdr.querySelector('h1, h2, h3, h4, h5, h6');
        return {
          index: index + 1,
          className: hdr.className,
          w3cRole: computedRole,
          headingTag: heading ? heading.tagName : '無 (Logo 導覽區)'
        };
      });

      const bannerCount = report.filter(r => r.w3cRole.startsWith('banner')).length;
      const h1Count = document.querySelectorAll('h1').length;

      console.log('=== [多重 Header 階層與無障礙角色檢驗報告] ===');
      console.log('全頁 <header> 總數:', allHeaders.length, '| 頂層 banner 地標數:', bannerCount, '| 全頁 <h1> 總數:', h1Count);
      report.forEach(r => {
        console.log(`#${r.index} .${r.className} ➔ W3C 角色: ${r.w3cRole} | 內部標題: ${r.headingTag}`);
      });
    }

    auditMultipleHeaders();
  </script>
</body>
</html>

Expected Output (預期 Console 輸出結果)

=== [多重 Header 階層與無障礙角色檢驗報告] ===
全頁 <header> 總數: 4 | 頂層 banner 地標數: 1 | 全頁 <h1> 總數: 1
#1 .site-header ➔ W3C 角色: banner (全站頂層地標) | 內部標題: 無 (Logo 導覽區)
#2 .article-header ➔ W3C 角色: generic (區段局部標頭) | 內部標題: H1
#3 .section-header ➔ W3C 角色: generic (區段局部標頭) | 內部標題: H2
#4 .comment-header ➔ W3C 角色: generic (區段局部標頭) | 內部標題: H3

五、 實務開發 4 大高頻踩坑雷區

在規劃複雜頁面的 多重 header 時,請特別留意以下 4 個實戰陷阱:

  1. 只有單獨一行 <h2> 或 <h3> 時,過度包裝多餘的 <header>(Header Wrapper Bloat):
    如果某個 <section> 開頭只有孤零零的一行 <h2>二、 系統需求</h2>,底下沒有任何副標題、沒有發布日期、也沒有操作按鈕,這時直接寫 <h2> 即可,不需要硬包一層 <header><h2>...</h2></header>!<header> 的價值在於「將標題與周圍的輔助介紹資訊(如 <hgroup>、<time>、作者、篩選按鈕)打包成一個語意群組」,單一元素多包一層只會增加無意義的 DOM 深度。
  2. 在 <footer> 裡面寫 <header>(語法驗證直接失敗):
    有些工程師在刻大型頁尾(Mega Footer)時,習慣在 <footer> 裡面的訂閱電子報區塊寫 <header><h3>訂閱技術週報</h3></header>。請注意:WHATWG <footer> 規範 (§4.3.8) 明文規定 <footer> 的後代元素中絕對禁止出現 <header> 或 <footer>!這不是風格問題,而是 W3C Nu Html Checker 會直接報紅字的語法錯誤。
  3. 把文章內文的第一段 <p> 誤包進 <article> 的 <header> 裡:
    <header> 僅限容納「介紹性導言(Lead / Deck)、副標題與中繼資料(作者、日期、目錄)」。文章真正的正文段落必須放在 <header> 結束標籤 </header> 之後,否則螢幕閱讀器與閱讀模式(Reader Mode,如 Safari 閱讀器或 Pocket)在擷取文章正文時,可能會把包在 <header> 裡的段落略過!
  4. 在 <body> 頂層放了兩個未被區段包裹的 <header>,導致雙重 banner 地標衝突:
    如前文所述,任何沒被 <article>、<section>、<aside>、<nav> 或 <main> 包住的 <header>,都會變成 role="banner" 頂層地標。根據 W3C 規範,一份文件最多只能有 1 個頂層 banner 地標;其餘局部 <header> 務必確認位於對應的區段容器內部。

六、 上線前 5 點自我檢驗清單 (Checklist)

在完成包含多重頁首的頁面切版後,請花 30 秒執行以下 5 點檢驗:

  • ☐ 1. 頂層 banner 地標唯一性檢查:確認整張網頁直接位於 <body> 底下的 <header> 只有 1 個,其餘 <header> 皆位於 <article>、<section>、<aside>、<nav> 或 <main> 內部。
  • ☐ 2. 全頁 <h1> 唯一性與標題遞進檢查:確認沒有誤信已廢除的 Document Outline 演算法而在多個 <header> 裡重複寫 <h1>;單篇內頁的唯一 <h1> 位於主文章 <article> > <header> 內,子章節依序使用 <h2> ➔ <h3>。
  • ☐ 3. 零 footer > header 或 header > header 非法嵌套:在 DevTools Console 執行 document.querySelectorAll('footer header, header header, address header').length === 0 確保回傳 true。
  • ☐ 4. 剔除單一標題的冗餘 <header> 外殼:檢查各 <section> 內的 <header>,若內部僅有單一 <h2> 而無任何副標題、導言或操作元件,已簡化為直接放置 <h2>。
  • ☐ 5. 瀏覽器閱讀模式(Reader Mode)實測:開啟 Safari 或 Firefox 的「閱讀模式」,確認文章主標題、作者日期與正文第一段皆能完整被擷取顯示,沒有因誤包進 <header> 而遺失正文。

參考資料與延伸閱讀

發表迴響