Sticky Nav 造成錨點連結被遮擋時,僅用幾行內聯 CSS 乾淨解決

在文件(部落格/維基/指南)中點擊腳註連結或目錄(TOC)時,瀏覽器會跳轉到 #some-id,並將該 id 所在元素對齊到視口頂端。

然而,若頁面上有使用 position: sticky(或 fixed)的導航欄,滾動會對齊到頂端,但實際內容卻被導航欄覆蓋,導致連結跳轉後內容不可見。

這是前端常見的問題,但對於後端或全棧工程師來說,看到「連結跳轉正常,但內容卻隱藏」的情況也頗為棘手。

本文將以我最常使用的「在問題頁面加入幾行內聯 CSS」方式(最簡單、即時)為主線,整理解決方案。


為什麼會發生這種情況?

瀏覽器的預設行為如下:

  • 當 URL 變為 .../page#target
  • 瀏覽器尋找 id="target" 的元素
  • 將該元素的起點對齊到滾動容器的起點(通常是視口頂端)

但 sticky nav 會覆蓋在視口上方,結果該元素被導航欄遮住。

鏈接目標被 sticky nav 遮擋的示例圖片


最簡單的解決方案:scroll-margin-top(為元素留出空隙)

給被錨點滾動到的元素加上 scroll-margin-top,瀏覽器會將該元素定位在「頂端加上空隙」的位置。

內聯 CSS 最小化(推薦)

在問題頁面的 <head> 或對應模板中加入以下樣式即可解決大多數情況。

<style>
  :root { --sticky-nav-h: 64px; } /* 將 nav 實際高度設為變數 */
  [id] { scroll-margin-top: calc(var(--sticky-nav-h) + 12px); }
</style>
  • --sticky-nav-h:sticky nav 的高度
  • + 12px:留出額外空隙,避免被完全遮擋(可自行調整)

若將 [id] 全域套用,頁面上所有錨點連結都會自動調整。 若覺得全域套用過於寬泛,可將範圍縮小至特定區塊。

範圍縮小,提升安全性

例如:僅在文章內容區塊內套用

<style>
  :root { --sticky-nav-h: 64px; }
  .article [id] { scroll-margin-top: calc(var(--sticky-nav-h) + 12px); }
</style>

若 TOC 主要跳轉至 h2/h3,可針對這些標題

<style>
  :root { --sticky-nav-h: 64px; }
  .article h2[id], .article h3[id] {
    scroll-margin-top: calc(var(--sticky-nav-h) + 12px);
  }
</style>

進階選項:scroll-padding-top(容器預設填充)

scroll-padding-top 用於「滾動捕捉/片段跳轉」等情境,提示滾動容器擁有「頂部安全區」。

實務上 scroll-margin-top 更直觀,但兩者結合可提升佈局穩定性。

<style>
  :root { --sticky-nav-h: 64px; }
  html { scroll-padding-top: calc(var(--sticky-nav-h) + 12px); }
</style>
  • 適合快速為整頁做「全域錨點調整」
  • 若需精細控制單一元素,仍建議使用 scroll-margin-top

兼容性/舊版方案:使用 ::before 創造偽偏移

這是早期常用的技巧:在錨點目標元素前插入隱藏區塊,讓實際位置向下移動,避開 nav。

<style>
  :root { --sticky-nav-h: 64px; }

  .anchor-target::before {
    content: "";
    display: block;
    height: calc(var(--sticky-nav-h) + 12px);
    margin-top: calc(-1 * (var(--sticky-nav-h) + 12px));
    visibility: hidden;
    pointer-events: none;
  }
</style>

使用範例:

<h2 id="install" class="anchor-target">安裝</h2>
  • 優點:原理簡單,舊版瀏覽器也能確保執行
  • 缺點:需為目標元素加 class,且選擇器較複雜

現今建議先嘗試 scroll-margin-top,若在特定環境失效,再考慮 ::before


JavaScript 方案?但「頁面級內聯 CSS」往往更勝一籌

當然也可以用 JavaScript:

element.scrollIntoView();
window.scrollBy(0, -navHeight);

但在以下情境下,CSS 更適合:

  • 文檔/靜態內容頁(腳註/TOC 膽大)
  • 不想改動框架或路由層,僅在特定頁面快速解決
  • 可能由非前端專業人員維護

內聯 <style> 具備「無依賴、易除錯、易回滾」的優勢,特別適用於文檔型頁面。


實務檢查清單

  • 正確測定 sticky nav 的高度
  • 若響應式改變高度,可在不同斷點調整 --sticky-nav-h
  • 不要過度擴大套用範圍
  • 雖然 [id] 全域套用方便,但建議限制於 .article [id] 等區塊
  • 留出「8~16px」的額外空隙,使用者感受更佳
  • 只給 nav 高度可能會讓內容緊貼,易被遮擋

結論:我最常用的單行解法

在問題頁面直接加入以下內聯樣式即可。

<style>
  :root { --sticky-nav-h: 64px; }
  .article [id] { scroll-margin-top: calc(var(--sticky-nav-h) + 12px); }
</style>

這樣即可一次性解決 TOC、腳註、深層連結等所有錨點被 nav 隱藏的問題。希望對想快速修復此問題的開發者有所幫助。


相關閱讀 - 圖片標籤中明確指定 width 與 height 的原因與效果 - 即使是後端工程師也必須知道的前端 JS 方法與模組最佳 5