透過 CSS 捲動 Snap 妥善控制捲動功能

宣告捲動貼齊位置,建立完善控管的捲動體驗。

CSS 捲動貼齊功能可讓網頁程式開發人員宣告捲動貼齊位置,打造完善控管的捲動體驗。分頁文章和圖片輪轉介面就是兩個常見的例子。CSS 捲動貼齊提供簡單易用且一致的 API,可用於建構這些熱門的使用者體驗模式。

背景

捲動貼齊的用途

捲動是與網頁內容互動的常見自然方式。這是平台的原生方式,可提供比畫面上一次顯示的資訊更多的資訊,在螢幕空間有限的行動平台上尤其重要。因此,網頁作者越來越傾向將內容整理成可捲動的平面清單,而非深層階層。

捲動的主要缺點是不夠精確。捲動畫面時,很少會剛好停在段落或句子的開頭。如果捲動在頁面或圖片中間結束,導致內容部分顯示,則對於具有明確邊界的分頁或分項內容,這種情況會更加明顯。這類用途適合採用可妥善控制的捲動體驗。

網頁程式開發人員長期以來都仰賴 JavaScript 解決方案來控制捲動,以解決這項缺點。不過,JavaScript 解決方案無法提供完整擬真度的解決方案,因為缺乏捲動自訂原始物件,或無法存取複合捲動。CSS 捲動貼齊可確保快速、高擬真且易於使用的解決方案,在各種瀏覽器中都能一致運作。

CSS 捲動貼齊可讓網頁作者為每個捲動容器標示捲動操作的結束邊界。接著,瀏覽器會根據捲動操作、捲動容器的版面配置和瀏覽權限,以及貼齊位置的詳細資料,選擇最合適的結束位置,然後順暢地以動畫方式呈現。回到先前的例子,當使用者捲動完輪轉介面時,可見圖片會貼齊位置。JavaScript 不需要調整捲動。

使用 CSS 捲動貼齊功能和圖片輪轉介面的範例。
搭配圖片輪轉介面使用 CSS 捲動貼齊的範例。 在這裡,捲動貼齊功能可確保捲動結束時,圖片的水平中心與捲動容器的水平中心對齊。

CSS 捲動貼齊

捲動貼齊是指在捲動操作完成後,調整捲動容器的捲動偏移,使其位於偏好的貼齊位置。

捲動容器可使用 scroll-snap-type 屬性啟用捲動貼齊功能。這會告知瀏覽器,應考慮將這個捲動容器貼齊至其子系產生的貼齊位置。scroll-snap-type 會決定捲動發生的軸:x、y 或 both,以及貼齊嚴格程度:mandatory、proximity。稍後會再詳細討論。

只要在元素上宣告所需對齊方式,即可產生貼齊位置。這個位置是捲動偏移量,最接近的上階捲動容器和元素會按照指定軸對齊。每個軸上可用的對齊方式如下:start、end、center。

start 對齊方式表示捲動容器貼齊點起始邊緣應與元素貼齊區域起始邊緣對齊。同樣地,end 和 center 對齊方式表示捲動容器貼齊點結束邊緣或中心,應與元素貼齊區域結束邊緣或中心對齊。

水平捲動軸上各種對齊方式的範例。

以下範例說明如何使用這些概念。

捲動貼齊的常見用途是圖片輪轉介面。舉例來說,如要建立橫向圖片輪轉介面,並在捲動時貼齊每張圖片,我們可以指定捲動容器在水平軸上具有強制 scroll-snap-type。將每張圖片設為 scroll-snap-align: center,確保貼齊功能將圖片置中於輪轉介面。

#gallery {
  scroll-snap-type: x mandatory;
  overflow-x: scroll;
  display: flex;
}

#gallery img {
   scroll-snap-align: center;
}
<div id="gallery">
  <img src="cat.jpg">
  <img src="dog.jpg">
  <img src="another_cute_animal.jpg">
</div>

由於貼齊位置與元素相關聯,因此貼齊演算法可以根據元素和捲動容器大小,智慧判斷貼齊的時間和方式。舉例來說,假設有一張圖片大於輪轉介面,如果使用簡單的貼齊演算法,使用者可能無法平移查看完整圖片。不過,規格要求實作項目偵測這種情況,並允許使用者在該圖片中自由捲動,只在圖片邊緣貼齊。

範例:歷程產品頁面

另一個可受益於捲動貼齊的常見案例,是具有多個邏輯區段可垂直捲動的頁面,例如一般的產品頁面。scroll-snap-type: y proximity; 更適合這類情況。當使用者捲動到特定區段的中間時,不會受到干擾,但當他們捲動到足夠接近的位置時,也會貼齊並引起對新區段的注意。

做法如下:

article {
  scroll-snap-type: y proximity;
  /* Reserve space for header plus some extra space for sneak peeking. */
  scroll-padding-top: 15vh;
  overflow-y: scroll;
}
section {
  /* Snap align start. */
  scroll-snap-align: start;
}
header {
  position: fixed;
  height: 10vh;
}
<article>
  <header> Header </header>
  <section> Section One </section>
  <section> Section Two </section>
  <section> Section Three </section>
</article>

捲動邊框間距和邊界

產品頁面有固定位置的頂端標頭。設計也要求在捲動容器貼齊時,頂端部分仍會顯示,以便向使用者提供上方內容的設計提示。

scroll-padding 屬性是新的 CSS 屬性,可用於調整捲動容器的有效可視區域 (或貼齊區),用於計算捲動貼齊對齊方式。這個屬性會定義相對於捲動容器內邊距方塊的內凹。在我們的範例中,頂端新增了 15vh 的額外插邊,指示瀏覽器將捲動容器頂端邊緣下方 15vh 的較低位置,視為捲動貼齊的垂直起始邊緣。貼齊時,貼齊目標元素的起始邊緣會與這個新位置對齊,因此上方會留有空間。

scroll-margin 屬性定義了用於調整貼齊目標有效方塊的起始量,類似於 scroll-padding 在貼齊捲動容器上的運作方式。

您可能已經注意到,這兩個屬性中沒有「snap」這個字。這是刻意設計,因為這些屬性實際上會修改所有相關捲動作業的方塊,而不只是捲動貼齊。舉例來說,Chrome 在計算 PageDown 和 PageUp 等分頁捲動作業的頁面大小,以及計算 Element.scrollIntoView() 作業的捲動量時,都會考量這些元素。

與其他捲動 API 互動

DOM Scrolling API

捲動貼齊會在所有捲動操作 (包括由指令碼啟動的操作) 之後發生。使用 Element.scrollTo 等 API 時,瀏覽器會計算作業的預期捲動位置,然後套用適當的貼齊邏輯,找出最終貼齊位置。因此,使用者指令碼不需要手動計算貼齊。

順暢捲動

順暢捲動可控制程式輔助捲動作業的行為,而捲動貼齊則可決定捲動的目的地。由於兩者控制捲動的正交層面,因此可以搭配使用,相輔相成。

過度捲動行為

過度捲動行為 API 可控制捲動在多個元素之間的鏈結方式,不受捲動貼齊影響。

注意事項和最佳做法

如果目標元素之間的距離很遠,請避免使用強制貼齊。這可能會導致貼齊位置之間的內容無法存取。

在許多情況下,您可以直接新增捲動貼齊功能,不必偵測功能。如有需要,請使用 @supports 或 CSS.supports 偵測是否支援 CSS 捲動貼齊。避免使用 scroll-snap-type,因為這也存在於已淘汰的規格中。

CSS 中的功能偵測

@supports (scroll-snap-align: start) {
  article {
    scroll-snap-type: y proximity;
    scroll-padding-top: 15vh;
    overflow-y: scroll;
  }
}

JavaScript 中的功能偵測

if (CSS.supports('scroll-snap-align: start')) {
  // use css scroll snap
} else {
  // use fallback
}

請勿假設程式輔助捲動 API (例如 Element.scrollTo) 一律會在要求的捲動偏移處結束。程式輔助捲動完成後,捲動貼齊功能可能會調整捲動偏移。請注意,即使在捲動貼齊之前,這也不是一個好的假設,因為捲動可能因其他原因而中斷,但捲動貼齊尤其如此。

未來工作

捲動體驗是 Chrome 團隊近期問卷調查的重點。問卷調查結果指出,有幾個領域需要額外努力,才能縮小外掛程式庫和 CSS 之間的差距。接下來的工作重點是scroll-snap,包括:

  1. API 在各瀏覽器的可用性和相容性。
  2. 開發新的 CSS API,例如 scroll-start。
  3. 處理新的 JS 事件,例如 snapChanged()。