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

TL;DR

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

Latar belakang

Batas scroll dan rantai scroll

Perantai scroll di Chrome Android.

Menggulir adalah salah satu cara paling mendasar untuk berinteraksi dengan suatu laman, tetapi pola UX tertentu bisa sulit untuk ditangani karena keunikan browser perilaku default. Sebagai contoh, ambil panel samping aplikasi yang memiliki banyak item yang mungkin harus di-scroll oleh pengguna. Ketika mereka mencapai bagian bawah, penampung tambahan menghentikan scroll karena tidak ada lagi konten untuk digunakan. Dengan kata lain, pengguna mencapai "batas scroll". Tetapi perhatikan apa yang terjadi jika pengguna terus men-scroll. Konten di belakang panel samping mulai di-scroll. Scroll adalah diambil alih oleh container induk; laman utama itu sendiri dalam contoh.

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

Efek tarik untuk refresh

Tarik untuk menyegarkan adalah gestur intuitif yang dipopulerkan oleh aplikasi seluler seperti Facebook dan Twitter. Menarik ke umpan sosial dan merilisnya akan membuat ruang untuk memuat postingan terbaru lainnya. Faktanya, UX yang sama menjadi sangat populer sehingga browser seluler seperti Chrome di Android telah mengadopsi efek yang sama. Menggeser ke bawah di bagian atas halaman akan menyegarkan seluruh halaman:

Tarik untuk refresh kustom Twitter
saat memuat ulang feed PWA mereka.
Tindakan tarik untuk refresh native Chrome Android
memperbarui seluruh kami.

Untuk situasi seperti PWA Twitter, mungkin masuk akal untuk menonaktifkan tindakan pull-to-refresh native. Mengapa? Di sini Anda tidak ingin pengguna memuat ulang halaman secara tidak sengaja. Ada juga potensi untuk melihat animasi refresh ganda. Atau, mungkin lebih baik menyesuaikan tindakan browser, menyelaraskannya lebih dekat dengan {i>branding.<i} Bagian yang kurang menguntungkan adalah bahwa jenis penyesuaian ini telah sulit untuk dilakukan. Pengembang akhirnya menulis {i> JavaScript <i}yang tidak perlu, menambahkan non-pasif pendengar sentuh (yang memblokir pengguliran), atau menempelkan seluruh laman dalam tegangan 100vw/vh <div> (untuk mencegah halaman kelebihan beban). Solusi ini memiliki negatif yang terdokumentasi dengan baik terhadap performa scroll.

Kita bisa lebih baik lagi!

Memperkenalkan overscroll-behavior

Properti overscroll-behavior adalah fitur CSS baru yang mengontrol perilaku apa yang terjadi saat Anda men-scroll container secara berlebihan (termasuk halaman itu sendiri). Anda dapat menggunakannya untuk membatalkan perantaian scroll, menonaktifkan/menyesuaikan tindakan pull-untuk-refresh, nonaktifkan efek rubberbanding di iOS (saat Safari mengimplementasikan overscroll-behavior), dan lainnya. Bagian terbaiknya adalah penggunaan overscroll-behavior tidak berdampak buruk performa halaman seperti tips yang disebutkan di bagian pengantar.

Properti ini memiliki tiga kemungkinan nilai:

  1. auto - Default. Scroll yang berasal dari elemen dapat disebarkan ke ancestor.
  2. contain - mencegah rantai scroll. Scroll tidak diterapkan ke ancestor tapi efek lokal dalam {i>node<i} ditampilkan. Misalnya, glow overscroll pada Android atau efek rubberbanding di iOS yang akan memberi tahu pengguna saat mereka mencapai batas scroll. Catatan: menggunakan overscroll-behavior: contain pada elemen html mencegah overscroll tindakan navigasi.
  3. none - sama seperti contain tetapi juga mencegah efek overscroll dalam node itu sendiri (mis. glow overscroll Android atau rubberbanding iOS).

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

Mencegah scroll meng-escape elemen posisi tetap

Skenario kotak chat

Konten di bawah jendela chat juga di-scroll :(

Pertimbangkan kotak chat yang diposisikan dengan tetap yang berada di bagian bawah halaman. Tujuan tujuannya adalah bahwa kotak chat adalah komponen mandiri dan dapat di-scroll secara terpisah dari konten di belakangnya. Namun, karena rantai scroll, dokumen mulai di-scroll segera setelah pengguna mengklik pesan terakhir dalam chat sejarah.

Untuk aplikasi ini, akan lebih tepat untuk memiliki scroll yang berasal dari kotak chat tetap ada dalam percakapan. Kita dapat mewujudkannya 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 proses menggulir {i>chatbox<i} konteks dan laman utama. Hasil akhirnya adalah bahwa laman utama tetap ditempatkan saat pengguna mencapai bagian atas/bawah histori chat. Scroll yang dimulai pada {i>chatbox<i} tidak menyebar.

Skenario overlay halaman

Variasi lain dari "underscroll" skenario ini adalah ketika Anda melihat konten men-scroll di belakang overlay posisi tetap. Hadiah sia-sia overscroll-behavior sudah benar! Browser mencoba bermanfaat tetapi yang akhirnya membuat situs terlihat penuh bug.

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

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

Menonaktifkan tarik untuk refresh

Menonaktifkan tindakan tarik untuk refresh adalah satu baris CSS. Cegah saja perantaian scroll di keseluruhan elemen yang menentukan area pandang. Dalam kebanyakan kasus, itu <html> atau <body>:

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

Dengan penambahan sederhana ini, kita memperbaiki animasi pull-to-refresh ganda di demo chatbox dan dapat sebagai gantinya, terapkan efek kustom yang menggunakan animasi pemuatan yang lebih rapi. Tujuan seluruh kotak masuk juga menjadi buram saat kotak masuk disegarkan:

Sebelum
Setelah

Berikut adalah cuplikan dari 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 overscroll dan rubberband

Untuk menonaktifkan efek pantulan saat mencapai 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: mencapai batas scroll akan menampilkan glow.
Setelah: glow dinonaktifkan.

Demo lengkap

Menyatukan semuanya, demo chatbox menggunakan overscroll-behavior untuk membuat animasi tarik untuk refresh kustom dan menonaktifkan scroll agar tidak keluar dari widget kotak chat. Hal ini memberikan gambaran pengalaman pengguna yang akan sulit dicapai tanpa CSS overscroll-behavior.

Lihat demo | Sumber