CSS position: sticky 失效?檢查祖先的 overflow-x: hidden
本文目錄
頁面上的小標題原本會黏在頂部,外層一加 overflow-x: hidden,它就跟著整頁滾走。打開 DevTools,檢查 sticky 元素祖先的 computed overflow。在一般包裝層,overflow-x: hidden 搭配預設的 overflow-y: visible 會把後者算成 auto。那層成了捲動容器,sticky 的參照也跟著變;實際被捲動的如果是整頁,標題就不會黏在視窗頂端。
用同一個頁面對照 hidden 和 clip
把下面存成 HTML,開啟後按「測試」。程式把頁面捲到同一位置,分別量兩次小標題離視窗上緣多遠。它也列出 overflow-y 的計算值,讓你確認只改橫軸宣告時,直軸是否跟著變化。
<!doctype html><html lang="zh-Hant"><meta charset="utf-8"><title>Sticky overflow 對照</title><style> body { margin: 0; } #run { position: fixed; right: 1rem; bottom: 1rem; z-index: 1; } #result { position: fixed; left: 1rem; bottom: 1rem; z-index: 1; background: white; } #wrapper { overflow-x: hidden; } #heading { position: sticky; top: 0; background: wheat; } .wide { width: 120%; height: 180vh; background: aliceblue; }</style><button id="run">測試</button><pre id="result"></pre><main id="wrapper"> <header id="heading">會黏住嗎?</header> <div class="wide"></div></main><script> const wrapper = document.querySelector("#wrapper"); const heading = document.querySelector("#heading"); function measure(value) { wrapper.style.overflowX = value; window.scrollTo(0, 120); return { overflowY: getComputedStyle(wrapper).overflowY, top: heading.getBoundingClientRect().top, }; } document.querySelector("#run").onclick = () => { const hidden = measure("hidden"); const clip = measure("clip"); document.querySelector("#result").textContent = JSON.stringify({ hidden, clip }); };</script>這份範例於 macOS 的 Chrome 157.0.8103.39 無介面模式執行,結果是 hidden 時直軸為 auto、top 為 −120;改為 clip 時直軸回到 visible、top 為 0。clip 仍裁掉橫向溢出,但這組雙軸設定不會讓包裝層成為捲動容器。這個例子使用一般祖先元素,根元素與 body 的 overflow 傳遞另有規則。
修法取決於哪一層要捲動
如果祖先只想裁掉背景裝飾,把裁切移到裝飾自己的包裝層,或在確認另一軸可保持 visible 時使用 overflow-x: clip。如果該層原本靠 scrollLeft 控制輪播,保留可捲動的容器:clip 不支援程式化捲動。也要看另一軸是否已用 auto、scroll 或 hidden。同版 Chrome 將 overflow-x: clip; overflow-y: auto 算成 clip / auto,直軸仍可成為捲動軸。要讓 sticky 參照視窗,需另外處理該層的直向捲動。
若需求是讓面板內的工具列黏在面板頂端,讓面板維持 overflow: auto 並限制高度,再捲面板驗收。若 sticky 已經正常,問題是點錨點或捲動吸附後被固定導覽列遮住,改查 scroll-padding 與 scroll-margin。
參考資料: