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

宣告捲動貼齊位置,建立控制良好的捲動體驗。

Robert Flack
Robert Flack
Majid Valipour
Majid Valipour

網頁開發人員可透過 CSS 捲動快照功能宣告捲動快照位置,打造控管良好的捲動體驗。分頁文章和圖片輪播是兩個常見的例子。CSS Scroll Snap 提供易於使用且一致的 API,可建構這些熱門的 UX 模式。

背景

捲動貼齊的用途

捲動是與網頁內容互動的常見方式,這是平台提供更多資訊的原始方式,可讓使用者一次查看更多內容,在螢幕空間有限的行動平台尤其重要。因此,網頁作者越來越傾向將內容整理成可捲動的扁平清單,而非深層階層,這並不令人意外。

捲動的主要缺點是精確度不足。捲動很少會與段落或句子對齊。如果捲動結束時,頁面或圖片只顯示一部分,這種情況在有意義的界線之間分頁或列出內容時會更加明顯。這些用途可受益於妥善控制的捲動體驗。

長期以來,網頁開發人員一直依賴以 JavaScript 為基礎的解決方案來控制捲動,以解決這項缺點。不過,由於缺少捲動自訂基本項目或複合捲動存取權,以 JavaScript 為基礎的解決方案無法提供完整保真度的解決方案。CSS Scroll Snap 可確保解決方案快速、高保真且易於使用,並在各瀏覽器中保持一致。

網頁作者可使用 CSS 捲動快照,為每個捲動容器標示捲動作業的完成界線。瀏覽器會根據捲動作業的詳細資料、捲動容器的版面配置和可見度,以及快速移動位置的詳細資料,選擇最合適的結束位置,然後平滑地動畫化至該位置。回到先前的例子,當使用者完成輪轉介面的捲動操作時,可見的圖片會自動對齊。JavaScript 不需調整捲動。

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

CSS 捲動貼齊

捲動對齊是指在捲動作業完成後,將捲動容器的捲動偏移量調整至偏好的對齊位置

捲動容器可以使用 scroll-snap-type 屬性選擇啟用捲動對齊功能。這會告知瀏覽器,應考慮將這個捲動容器對齊後代元素產生的對齊位置。scroll-snap-type 可決定捲動發生的軸:xyboth,以及對齊嚴格程度:mandatoryproximity。稍後會再詳細說明。

只要在元素上宣告所需對齊方式,即可產生對齊位置。這個位置是捲動偏移量,最接近的祖先捲動容器和元素會根據指定軸對齊。每個軸上可進行下列對齊:startendcenter

start 對齊方式是指捲動容器的對齊點起點邊緣,應與元素對齊區域的起點邊緣齊平。同樣地,endcenter 對齊方式表示捲動容器的貼齊點終點邊緣或中心點,應與元素貼齊區域的終點邊緣或中心點對齊。

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

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

捲動貼齊的常見用途是圖片輪播。舉例來說,如要建立水平圖片輪播,讓使用者捲動時會自動對齊每張圖片,我們可以將捲動容器指定為在水平軸上強制對齊 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 可控制捲動在多個元素間的串連方式,且不會受到捲動吸附影響。

注意事項和最佳做法

如果目標元素間距較大,請避免使用強制對齊。 這可能會導致無法存取兩個對齊位置之間的內容。

在許多情況下,捲動貼齊功能可做為強化功能新增,不需要進行功能偵測。如有需要,請使用 @supportsCSS.supports 偵測 CSS Scroll Snap 的支援情形。 請避免使用 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()