Kendalikan scroll Anda - menyesuaikan efek pull-to-refresh dan overflow

TL;DR (Ringkasan)

Properti CSS overscroll-behavior memungkinkan developer mengganti perilaku scroll tambahan default browser saat mencapai bagian atas/bawah konten. Kasus penggunaan mencakup penonaktifan fitur pull-to-refresh di perangkat seluler, menghapus efek glow overscroll dan rubberbanding, serta mencegah konten halaman di-scroll saat berada di bawah modal/overlay.

Latar belakang

Batas scroll dan rantai scroll

Perantaian scroll di Chrome Android.

Scrolling adalah salah satu cara paling mendasar untuk berinteraksi dengan halaman, tetapi pola UX tertentu bisa sulit ditangani karena perilaku default browser yang unik. Sebagai contoh, ambil panel samping aplikasi yang berisi banyak item yang mungkin harus di-scroll oleh pengguna. Saat mencapai bagian bawah, penampung tambahan akan berhenti men-scroll karena tidak ada lagi konten untuk digunakan. Dengan kata lain, pengguna mencapai "batas scroll". Namun, perhatikan apa yang terjadi jika pengguna terus men-scroll. Konten di belakang panel samping mulai men-scroll! Scrolling diambil oleh penampung induk; halaman utama itu sendiri dalam contoh.

Ternyata perilaku ini disebut scroll chaining; perilaku default browser saat men-scroll konten. Sering kali {i>default-<i}nya cukup bagus, tetapi terkadang tidak diinginkan atau bahkan tidak diharapkan. Aplikasi tertentu mungkin ingin memberikan pengalaman pengguna yang berbeda saat pengguna mencapai batas scroll.

Efek tarik untuk refresh

Tarik untuk refresh adalah gestur intuitif yang dipopulerkan oleh aplikasi seluler, seperti Facebook dan Twitter. Menarik ke bawah pada feed sosial dan melepaskannya akan menciptakan ruang baru untuk postingan yang lebih baru untuk dimuat. Faktanya, UX khusus ini menjadi sangat populer sehingga browser seluler seperti Chrome di Android telah menggunakan efek yang sama. Menggeser ke bawah di bagian atas halaman akan memuat ulang seluruh halaman:

pull-to-refresh kustom Twitter
saat memuat ulang feed di PWA mereka.
Tindakan pull-to-refresh native Chrome Android
akan memuat ulang seluruh halaman.

Untuk situasi seperti PWA Twitter, sebaiknya nonaktifkan tindakan pull-to-refresh native. Mengapa demikian? Dalam aplikasi ini, Anda mungkin tidak ingin pengguna memuat ulang halaman secara tidak sengaja. Ada juga potensi untuk melihat animasi refresh ganda. Atau, mungkin akan lebih baik untuk menyesuaikan tindakan browser, dengan menyesuaikannya lebih dekat dengan branding situs. Bagian yang tidak menguntungkan adalah jenis penyesuaian ini sulit dilakukan. Developer akhirnya menulis JavaScript yang tidak perlu, menambahkan pemroses sentuh non-pasif (yang memblokir scroll), atau menempelkan seluruh halaman dalam <div> 100vw/vh (untuk mencegah halaman meluap). Solusi ini memiliki efek negatif yang terdokumentasi dengan baik terhadap performa scroll.

Kita bisa melakukan yang lebih baik!

Memperkenalkan overscroll-behavior

Properti overscroll-behavior adalah fitur CSS baru yang mengontrol perilaku yang terjadi saat Anda men-scroll penampung secara berlebihan (termasuk halaman itu sendiri). Anda dapat menggunakannya untuk membatalkan pembuatan rantai scroll, menonaktifkan/menyesuaikan tindakan tarik untuk refresh, menonaktifkan efek rubberbanding di iOS (saat Safari mengimplementasikan overscroll-behavior), dan lainnya. Bagian terbaiknya adalah menggunakan overscroll-behavior tidak akan memengaruhi performa halaman seperti tips yang disebutkan di pengantar.

Properti ini mengambil tiga kemungkinan nilai:

  1. auto - Default. Scroll yang berasal dari elemen dapat menyebar ke elemen ancestor.
  2. contain - mencegah scroll chain. Scroll tidak menyebar ke ancestor, tetapi efek lokal dalam node akan ditampilkan. Misalnya, efek glow overscroll pada Android atau efek rubberbanding di iOS yang memberi tahu pengguna saat mereka telah mencapai batas scroll. Catatan: penggunaan overscroll-behavior: contain pada elemen html akan mencegah tindakan navigasi overscroll.
  3. none - sama seperti contain tetapi juga mencegah efek overscroll dalam node itu sendiri (misalnya glow overscroll Android atau rubberbanding iOS).

Mari pelajari beberapa contoh untuk melihat cara menggunakan overscroll-behavior.

Mencegah scroll keluar dari elemen posisi tetap

Skenario kotak chat

Konten di bawah jendela chat juga di-scroll :(

Pertimbangkan kotak chat yang diposisikan tetap yang terletak di bagian bawah halaman. Tujuannya adalah agar chatbox merupakan komponen mandiri dan di-scroll secara terpisah dari konten di belakangnya. Namun, karena rantai scroll, dokumen akan mulai di-scroll segera setelah pengguna membuka pesan terakhir dalam histori chat.

Untuk aplikasi ini, lebih tepat untuk memiliki scroll yang berasal dari kotak chat agar tetap berada dalam chat. Kita dapat melakukannya dengan menambahkan overscroll-behavior: contain ke elemen yang menyimpan pesan chat:

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

Pada dasarnya, kita membuat pemisahan logis antara konteks scroll chatbox dan halaman utama. Hasil akhirnya adalah halaman utama tetap berada di posisi teratas saat pengguna mencapai bagian atas/bawah histori chat. Scroll yang dimulai di kotak chat tidak akan disebarkan.

Skenario overlay halaman

Variasi lain dari skenario "underscroll" adalah saat Anda melihat konten di-scroll di belakang overlay posisi tetap. Hadiah mati overscroll-behavior sudah berlangsung. {i>Browser<i} mencoba membantu tetapi akhirnya membuat situs tampak bermasalah.

Contoh - modal dengan dan tanpa overscroll-behavior: contain:

Sebelum: konten halaman di-scroll di bawah overlay.
Setelah: konten halaman tidak dapat di-scroll di bawah overlay.

Menonaktifkan fitur tarik untuk refresh

Penonaktifan tindakan pull-to-refresh adalah satu baris CSS. Cukup cegah pembuatan rantai scroll di seluruh elemen penentu area pandang. Dalam sebagian besar kasus, nilainya adalah <html> atau <body>:

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

Dengan tambahan sederhana ini, kita akan memperbaiki animasi pull-to-refresh ganda dalam demo chatbox dan sebagai gantinya, dapat menerapkan efek kustom yang menggunakan animasi pemuatan yang lebih rapi. Seluruh kotak masuk juga akan menjadi buram saat kotak masuk dimuat ulang:

Sebelum
Setelah

Berikut cuplikan kode lengkap:

<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>

Menonaktifkan efek glow dan rubberbanding overscroll

Untuk menonaktifkan efek pantulan saat menekan batas scroll, gunakan overscroll-behavior-y: none:

body {
  /* Disables pull-to-refresh and overscroll glow effect.
     Still keeps swipe navigations. */
  overscroll-behavior-y: none;
}
Sebelum: menekan batas scroll akan menampilkan glow.
Setelah: glow dinonaktifkan.

Demo lengkap

Dengan menggabungkan semuanya, demo chatbox lengkap menggunakan overscroll-behavior untuk membuat animasi pull-to-refresh kustom dan menonaktifkan scroll agar tidak keluar dari widget kotak chat. Hal ini memberikan pengalaman pengguna optimal yang sulit dicapai tanpa CSS overscroll-behavior.

Lihat demo | Sumber