掌控捲動方式 - 自訂下拉即可重新整理和溢位效果

Eric Bidelman
Majid Valipour

重點摘要

CSS overscroll-behavior 屬性可讓開發人員在到達內容的頂端/底部時,覆寫瀏覽器的預設溢位捲動行為。應用實例包括停用行動裝置上的提取即可重新整理功能、移除過度捲動光暈和橡皮帶效果,以及避免網頁內容在強制回應/重疊下方時捲動。

背景

捲動界線和捲動鏈結

Chrome Android 上的捲動鏈結。

捲動是與頁面互動最基本的方法之一,但某些使用者體驗模式可能會因為瀏覽器的特殊預設行為而難以處理。舉例來說,假設應用程式導覽匣中有大量項目,使用者必須捲動瀏覽。當容器捲動到底部時,溢位容器就會停止捲動,因為沒有其他內容可供使用。換句話說,使用者會到達「捲動界線」。不過請注意,如果使用者繼續捲動,會發生什麼情況。導覽匣後方的內容!捲動是由父項容器 (範例中為主頁面) 移動。

而這項行為稱為「捲動鏈結」;瀏覽器在捲動內容時的預設行為。預設值通常很美,但有時並不適合,甚至非預期中。部分應用程式可能會想在使用者點選捲動界線時提供不同的使用者體驗。

下拉即可重新整理效果

提取式重新整理是一種直觀的手勢,廣受行動應用程式 (例如 Facebook 和 Twitter) 使用。將社群媒體動態消息向下拉並放開時,會建立新空間來載入較近期的貼文。事實上,這種使用者體驗已經大受歡迎,Android 版 Chrome 等行動瀏覽器也開始採用同樣的效果。在頁面頂端向下滑動可重新整理整個頁面:

Twitter 的自訂下拉即可重新整理
功能,在 PWA 中重新整理動態消息時。
Chrome Android 內建的提取即可重新整理操作
會重新整理整個頁面。

如果是 Twitter PWA 這類的情況,建議您停用原生的提取即可重新整理動作。原因何在?在這個應用程式中,您可能都不希望使用者不小心重新整理頁面。同時也會顯示雙重重新整理動畫!或者,您也可以自訂瀏覽器動作,使其更符合網站的品牌宣傳元素。不幸的是,這類自訂功能已經很複雜,因此會停用。開發人員最後會編寫不必要的 JavaScript、新增非被動式 觸控事件監聽器 (這會禁止捲動畫面),或將整個頁面固定在 100vw/vh 中,以免網頁溢位。<div>這些解決方法已充分記錄對捲動效能的負面影響。

我們可以做得更好!

隆重推出 overscroll-behavior

overscroll-behavior 屬性是新的 CSS 功能,可控制過度捲動容器 (包括網頁本身) 時的行為。您可以用來取消捲動鏈結、停用/自訂提取重新整理動作、停用 iOS 上的橡皮帶效果 (Safari 實作 overscroll-behavior 時) 等等。最棒的是,使用 overscroll-behavior 不會對網頁效能造成負面影響,例如簡介中提到的駭客入侵!

屬性接受三個可能的值:

  1. auto:預設值。源自該元素的捲動可套用至祖系元素。
  2. 包含 - 防止捲動鏈結。捲動不會套用至祖系,但會顯示節點中的本機效果。例如,Android 上的過度捲動光暈效果,或 iOS 上的橡皮帶效果,會在使用者達到捲動邊界時通知使用者。注意:在 html 元素上使用 overscroll-behavior: contain 可避免過度捲動導覽動作。
  3. none - 與 contain 相同,但也會防止節點本身內部的過度捲動效果 (例如 Android 過度捲動光暈或 iOS 橡皮帶)。

讓我們深入探討一些使用 overscroll-behavior 的範例。

避免捲動逸出固定位置元素

即時通訊方塊情境

即時通訊視窗下方的內容也會捲動 :(

假設有一個位於頁面底部的固定位置即時通訊方塊,這種做法的用意是聊天方塊是獨立元件,而且會分開捲動畫面來瀏覽內容。不過,由於捲動鏈結,文件會在使用者點選聊天記錄中的最後一則訊息時開始捲動。

就這個應用程式而言,讓使用者在即時通訊方塊中的捲動畫面更適合留在即時通訊內。只要將 overscroll-behavior: contain 新增至存放即時通訊訊息的元素即可:

#chat .msgs {
  overflow: auto;
  overscroll-behavior: contain;
  height: 300px;
}

基本上,我們會為聊天方塊的捲動內容和主頁面建立邏輯區隔。因此,當使用者到達聊天記錄的頂端/底部時,主頁面就會一直顯示。在聊天室中開始的捲動不會傳播。

網頁重疊情境

「隱藏捲動」情境的另一個變化版本,是當您看到內容在固定位置重疊後方捲動時。致命贈品 overscroll-behavior 已正式上路!瀏覽器致力提供實用的服務,但最終會導致網站看起來有錯誤。

範例 - 包含及不含 overscroll-behavior: contain 的互動視窗:

變更前:網頁內容會捲動到重疊下方。
之後:網頁內容不會捲動至重疊下方。

停用下拉即可重新整理功能

關閉下拉即可重新整理動作是 CSS 單行。只要避免對整個可視區域定義元素進行捲動鏈結即可。在多數情況下,也就是 <html><body>

body {
  /* Disables pull-to-refresh but allows overscroll glow effects. */
  overscroll-behavior-y: contain;
}

透過這個簡單的新增內容,我們修正了聊天方塊示範中的雙下拉即可重新整理動畫,並可以改為實作使用後載入動畫的自訂效果。整個收件匣也會隨著收件匣重新整理的情況進行模糊處理:

變更前
變更後

以下是完整程式碼的程式碼片段:

<style>
  body.refreshing #inbox {
    filter: blur(1px);
    touch-action: none; /* prevent scrolling */
  }
  body.refreshing .refresher {
    transform: translate3d(0,150%,0) scale(1);
    z-index: 1;
  }
  .refresher {
    --refresh-width: 55px;
    pointer-events: none;
    width: var(--refresh-width);
    height: var(--refresh-width);
    border-radius: 50%;
    position: absolute;
    transition: all 300ms cubic-bezier(0,0,0.2,1);
    will-change: transform, opacity;
    ...
  }
</style>

<div class="refresher">
  <div class="loading-bar"></div>
  <div class="loading-bar"></div>
  <div class="loading-bar"></div>
  <div class="loading-bar"></div>
</div>

<section id="inbox"><!-- msgs --></section>

<script>
  let _startY;
  const inbox = document.querySelector('#inbox');

  inbox.addEventListener('touchstart', e => {
    _startY = e.touches[0].pageY;
  }, {passive: true});

  inbox.addEventListener('touchmove', e => {
    const y = e.touches[0].pageY;
    // Activate custom pull-to-refresh effects when at the top of the container
    // and user is scrolling up.
    if (document.scrollingElement.scrollTop === 0 && y > _startY &&
        !document.body.classList.contains('refreshing')) {
      // refresh inbox.
    }
  }, {passive: true});
</script>

停用過度捲動光暈和橡皮帶效果

如要停用達到捲動界線時的彈跳效果,請使用 overscroll-behavior-y: none

body {
  /* Disables pull-to-refresh and overscroll glow effect.
     Still keeps swipe navigations. */
  overscroll-behavior-y: none;
}
變更前:按下捲動界線時顯示光暈。
變更後:無法使用光暈。

完整展示模式

總而言之,完整的聊天方塊示範會使用 overscroll-behavior 建立自訂的下拉即可重新整理動畫,並避免捲動造成聊天方塊小工具的捲動。如果不使用 CSS overscroll-behavior,而使用者可能難以達成這個目標,才能提供最佳使用者體驗。

查看示範 | 來源