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

重點摘要

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. contain - 防止捲動鏈結。捲動不會套用至祖系,但會顯示節點內的本機效果。舉例來說,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 是難以達成的。

查看示範 | 來源