CSS overflow: auto clip 怎麼用?單軸捲動與 sticky 邊界
很多水平卡片、表格或畫布元件,其實只需要左右捲動;但常見的 overflow: auto 會讓上下軸也成為可捲動軸,overflow: hidden 又可能讓 position: sticky 找到你不想要的祖先。結果就是 header 不再貼住預期位置,或觸控手勢在巢狀容器間互相搶事件。
直接答案是:水平元件先用 overflow: auto clip 表達「x 軸可捲動、y 軸只裁切」;針對要允許斜向手勢的地圖或放大圖片,再評估 scroll-axis-lock: none。兩者目前都不該被當成所有瀏覽器都已支援的 production 基線。
Chrome 153 release notes 將 single-axis scroll containers 標示為非穩定 channel 功能;scroll-axis-lock 也來自 CSS Overflow Level 5 的新規範。請把 feature detection、fallback 與真實裝置測試一起納入元件設計。
先分清楚三種 overflow 意圖
| 寫法 | 主要意圖 | 常見代價 |
|---|---|---|
overflow: auto | 兩軸都可能需要捲動 | 產生不必要的第二個 scroll axis,sticky 邊界較難推理 |
overflow: hidden | 隱藏溢出內容 | 可能建立你不想要的滾動祖先,且鍵盤或程式捲動行為容易被誤判 |
overflow: auto clip | 一軸可捲動,另一軸裁切 | 新語法仍需檢查瀏覽器支援與 fallback |
這不是把內容「藏起來」的視覺技巧,而是把 scrollability 寫進 layout contract。你要先決定哪一個軸真的可以被使用者操作,再選擇 CSS。
水平卡片用 auto clip
先建立不依賴特定框架的 HTML:
<section class="board" aria-labelledby="board-title"> <h2 id="board-title" class="board__title">功能總覽</h2> <div class="board__track"> <article class="card">第一張卡片</article> <article class="card">第二張卡片</article> <article class="card">第三張卡片</article> </div></section>如果是整個 board 負責水平捲動,最小配置可以是:
.board { overflow: auto clip; overscroll-behavior-inline: contain;}
.board__track { display: flex; gap: 1rem; inline-size: max-content; min-inline-size: 100%;}
.card { flex: 0 0 min(80vw, 24rem);}overflow shorthand 的兩個值分別對應物理 x 軸與 y 軸,不隨 LTR/RTL 或 writing mode 交換;auto clip 因此代表 x 可捲動、y 裁切。若元件需要支援不同 writing mode,請把這段意圖改寫成 overflow-inline: auto 與 overflow-block: clip,並實際檢查瀏覽器對 logical properties 的支援。
如果內容只應該在 x 軸移動,也可以把物理軸寫得更直白:
.board { overflow-x: auto; overflow-y: clip;}這種寫法適合先表達設計意圖,但不能跳過 @supports 與 fallback 測試;新舊瀏覽器對「一軸 scrollable、另一軸 clip」的處理可能不同。
為什麼它能幫 sticky 少走錯路
position: sticky 不是固定在 viewport;它會受祖先的 scroll container、inset 與可用空間限制。當外層只因為 overflow: auto 意外建立 y 軸 scroll container,sticky header 可能就跟著錯誤的祖先計算。
一個簡化的 header 範例:
.board__title { position: sticky; inset-block-start: 0; z-index: 1; background: Canvas;}auto clip 的價值,是讓 layout 明確表示某一軸只能裁切,瀏覽器才有機會把 sticky 的不同軸邊界分開計算。但它不會自動修好所有 sticky 問題;仍要檢查祖先是否有 transform、contain、額外的 overflow、固定高度與 stacking context。
排錯時先在 DevTools 逐層暫時移除 overflow,再確認是哪一個祖先在目標軸真的可捲動。不要只把 z-index 調大,因為那通常解不了錯誤的 scroll ancestor。
scroll-axis-lock 適合另一種互動
瀏覽器常會把觸控捲動手勢鎖到主要移動軸,避免使用者想左右滑時不小心上下漂移。CSS Overflow Level 5 的 scroll-axis-lock 允許作者在需要「斜向也能持續捲動」的 scroll container 上關閉這個鎖定:
.map-or-zoomed-image { scroll-axis-lock: none;}這比較適合地圖、放大圖片或需要同時操作兩軸的畫布,不是一般水平 carousel 的預設值。普通卡片列通常應保留軸向鎖定,讓觸控操作更容易預期。
Feature detection 與 fallback
先保留可操作的 fallback。下方 @supports 只能確認宣告是否被接受,不能單獨驗證單軸捲動:
.board { overflow-x: auto; overflow-y: hidden;}
@supports (overflow: auto clip) { .board { overflow: auto clip; }}
@supports (scroll-axis-lock: none) { .map-or-zoomed-image { scroll-axis-lock: none; }}fallback 使用 hidden 時,語意不等同於 clip;它可能仍參與 scroll container 計算。因此 fallback 的目標是讓舊瀏覽器能操作,而不是假裝兩種行為完全一樣。若 sticky 是核心需求,請在 fallback browser 上單獨驗收 header 邊界。
語法通過之後,還要看 clip 有沒有變成 hidden
MDN 的 overflow 計算值規則記載:當另一軸不是 visible 或 clip,clip 會計算成 hidden。因此,既有實作也可能接受 overflow: auto clip 的語法,卻仍以 auto hidden 運作。僅看 @supports 成立,會把語法支援誤當成新的單軸行為。
Chrome 153 公告的單軸功能改變的是可捲動值與 clip 搭配的行為;公告連結的 CSSWG 修訂也處理各軸的 scroll container 邊界。本文沒有實測各瀏覽器,不能列出哪個穩定版本已符合全部行為。
可在實際測試頁的 DevTools Console 檢查文章範例:
const board = document.querySelector('.board');if (!board) throw new Error('找不到 .board 測試元素');const style = getComputedStyle(board);console.table({ acceptsSyntax: CSS.supports('overflow', 'auto clip'), computedX: style.overflowX, computedY: style.overflowY, writingMode: style.writingMode,});這段是尚未執行的瀏覽器診斷示例。如果語法為 true,但 computedY 是 hidden,就不能以它證明 y 軸仍是 clip。若 computedY 是 clip,也還要檢查真正溢出的內容、捲動操作及 sticky:沒有溢出時畫面不動,並不是功能成立的證據;其他樣式規則也可能蓋掉目標宣告。
依序記錄「宣告是否接受 → computed value → 實際操作」,才有可交接的相容性結果。若某個目標瀏覽器仍採舊行為,讓 sticky header 留在水平 track 的捲動元素外,是可以另外驗收的降級結構;不要依靠同一個語法查詢強迫啟用實驗行為。
上線前的四組測試
- 滑鼠與觸控:水平拖曳不會把頁面垂直位置帶走;需要雙軸的地圖仍能斜向操作。
- 鍵盤:focus 進入卡片後,Tab、方向鍵與可見 focus ring 都能到達被裁切內容。
- sticky:在短內容、長內容、巢狀 overflow、縮放與不同 viewport 高度逐一檢查。
- 支援矩陣:至少測試 stable browser、Chrome 153 對應的實驗 channel、iOS/Android 觸控與沒有新語法的 fallback。
如果元件還需要 snap、marker 或按鈕導覽,可以接著看 CSS Scroll Marker 建立可存取輪播導覽;不要把實驗中的 marker API 與單軸 overflow 當成同一個功能。
參考資料:
Chrome for Developers:Chrome 153 release notes