CSS Scroll Snap 怎麼避開固定導覽列:scroll-padding 與 scroll-margin
CSS Scroll Snap 很適合橫向卡片列、逐頁閱讀與章節導覽;實作後卻常出現一個更惱人的問題:捲動確實吸附了,但目標標題被固定導覽列蓋住。
關鍵是分清楚設定位置:scroll-snap-type 和 scroll-padding 放捲動容器;scroll-snap-align 和 scroll-margin 放每一個吸附目標。 不要用 JavaScript 再算一次 header 高度來修正 CSS 本可描述的捲動邊界。
先建立真的能捲動的容器
<div class="story-list"> <article class="story-card">第一段</article> <article class="story-card">第二段</article> <article class="story-card">第三段</article></div>.story-list { display: grid; grid-auto-flow: column; grid-auto-columns: 85%; gap: 1rem; overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-inline: 1rem;}
.story-card { scroll-snap-align: start;}Scroll Snap 的前提是容器有可捲動範圍。mandatory 會要求結束位置對齊 snap point;若讀者需要停在兩個項目間讀較長內容,可考慮 proximity,讓瀏覽器只在接近目標時吸附。
固定 header 用 scroll-padding-top
頁面本身是捲動容器時,可把已知的 header 高度變成 scrollport 的內距:
:root { --header-height: 4.5rem;}
html { scroll-snap-type: y proximity; scroll-padding-top: var(--header-height);}
article h2 { scroll-snap-align: start;}這個設定也會影響 scrollIntoView() 與 fragment navigation 的可視對齊;它描述的是「容器的可用可視區域」,所以放在 html 或真正有 overflow 的面板,而不是隨意放到每個標題。
若只有某個錨點需要額外空間,例如 heading 上方有小型分類列,才在目標用 scroll-margin-top:
#pricing { scroll-margin-top: calc(var(--header-height) + 1rem);}輪播別只靠強制吸附
Scroll Snap 解決的是捲動落點,不會替你補上輪播的可存取操作。若卡片是可互動內容,至少要讓鍵盤能移動到卡片內的連結或按鈕;不要把資訊只放在滑動才能看到的區塊。也要用實機檢查觸控板、鍵盤與 reduced motion 偏好下的感受。
如果問題是「呼叫 scrollIntoView() 後沒有捲到正確元素」,先確認你拿到的是單一 DOM element,而不是先把 CSS 吸附規則當成錯誤來源;可搭配 scrollIntoView 常見錯誤與定位方式 排查。
參考資料:
回報錯字、失效連結,或告訴我你想看的延伸主題。