TL;DR
Właściwość CSS overscroll-behavior
pozwala deweloperom zastąpić domyślne zachowanie przewijania przy przepełnieniu w przeglądarce, gdy użytkownik dotrze do góry lub dołu treści. Przykłady zastosowań obejmują wyłączenie funkcji przeciągania do odświeżenia na urządzeniach mobilnych, usunięcie efektu poświaty i efektu gumki oraz uniemożliwienie przewijania zawartości strony, gdy znajduje się ona pod modalem lub nakładką.
Tło
Granice przewijania i łańcuchowanie przewijania
Przewijanie jest jednym z podstawowych sposobów interakcji ze stroną, ale niektóre wzorce UX mogą być trudne do zastosowania ze względu na dziwaczne domyślne zachowania przeglądarki. Weźmy na przykład szufladę aplikacji z dużą liczbą elementów, które użytkownik może przewijać. Gdy użytkownik dotrze do dołu, przewijanie kontenera przepełnionego treściami zostanie zatrzymane, ponieważ nie ma już więcej treści do wyświetlenia. Innymi słowy, użytkownik osiąga „granicę przewijania”. Zwróć uwagę, co się dzieje, gdy użytkownik przewija dalej. Treści za szufladą zaczynają się przewijać. Przewijanie jest przejmowane przez kontener nadrzędny, czyli w tym przykładzie przez stronę główną.
Okazuje się, że to zachowanie nazywa się łańcuchowanie przewijania. Jest to domyślne zachowanie przeglądarki podczas przewijania treści. Często domyślne ustawienia są całkiem dobre, ale czasami nie jest to pożądane, a nawet nieoczekiwane. Niektóre aplikacje mogą zapewniać użytkownikom inne wrażenia, gdy dotrą do granicy przewijania.
Efekt „przeciągnij, aby odświeżyć”
Przeciąganie w dół w celu odświeżenia jest intuicyjnym gestem znanym z aplikacji mobilnych, takich jak Facebook czy Twitter. Przeciągnięcie w dół i puszczenie palca powoduje utworzenie nowego miejsca na załadowanie nowszych postów. W fakcie ten interfejs użytkownika stał się tak popularny, że przeglądarki mobilne, takie jak Chrome na Androidzie, zaczęły stosować ten sam efekt. Przesunięcie palcem w dół u góry strony spowoduje odświeżenie całej strony:
W sytuacjach takich jak PWA na Twitterze warto wyłączyć natywne działanie „przeciągnij, by odświeżyć”. Dlaczego? W tej aplikacji prawdopodobnie nie chcesz, aby użytkownik przypadkowo odświeżał stronę. Możesz też zobaczyć podwójną animację odświeżania. Lepszym rozwiązaniem może być dostosowanie działania przeglądarki do marki witryny. Niestety ten typ dostosowywania jest trudny do wykonania. Deweloperzy muszą pisać niepotrzebny kod JavaScript, dodawać niepasywne metody obsługi dotyku (które blokują przewijanie) lub umieszczać całą stronę w ramach 100 vw/vh<div>
(aby zapobiec jej przepełnianiu). Te obejścia mają dobrze udokumentowany negatywny wpływ na wydajność przewijania.
Możemy to zrobić lepiej.
Przedstawiamy overscroll-behavior
Właściwość overscroll-behavior
to nowa funkcja CSS, która kontroluje to, co dzieje się, gdy przewiniesz kontener (w tym samą stronę) zbyt mocno. Możesz go użyć, aby anulować łańcuch przewijania, wyłączyć lub dostosować funkcję przewijania przez pociągnięcie, wyłączyć efekt gumki na iOS (gdy Safari wdroży overscroll-behavior
) i wykonywać inne czynności.
Najlepsze jest to, że użycie overscroll-behavior
nie wpływa negatywnie na
wydajność strony, tak jak sztuczki wymienione we wstępie.
Właściwość może przyjmować 3 wartości:
- auto – wartość domyślna. Przewijanie, które pochodzi z elementu, może być przekazywane do elementów nadrzędnych.
- contain – zapobiega łańcuchom przewijania. Przewijanie nie jest przekazywane do przodków, ale wyświetlane są efekty lokalne w węźle. Na przykład efekt poświaty przy przewijaniu na Androidzie lub efekt gumki na iOS, który informuje użytkownika, gdy osiągnie on granicę przewijania. Uwaga: użycie
overscroll-behavior: contain
w elemenciehtml
zapobiega dalekim przewijaniu. - none (brak) – to samo co
contain
, ale zapobiega też efektom przewijania w ramach węzła (np. efekt poświaty przy przewijaniu na Androidzie lub efekt gumki na iOS).
Przyjrzyjmy się kilku przykładom, aby dowiedzieć się, jak używać atrybutu overscroll-behavior
.
Zapobiegaj zmianie znaczenia elementów w stałej pozycji podczas przewijania
Scenariusz czatu
Rozważ użycie okna czatu w stałym położeniu na dole strony. Chodzi o to, aby okno czatu było samodzielnym elementem, który można przewijać niezależnie od treści znajdujących się za nim. Jednak ze względu na łańcuch przewijania dokument zaczyna się przewijać, gdy tylko użytkownik kliknie ostatnią wiadomość w historii czatu.
W przypadku tej aplikacji przewijanie pochodzące z pola czatu powinno pozostać na czacie. Aby to zrobić, dodaj overscroll-behavior: contain
do elementu, który zawiera wiadomości czatu:
#chat .msgs {
overflow: auto;
overscroll-behavior: contain;
height: 300px;
}
W podstawie chodzi o logiczne oddzielenie kontekstu przewijania czatu od strony głównej. W efekcie strona główna pozostaje na swoim miejscu, gdy użytkownik dotrze do góry lub do dołu historii czatu. Przewijanie, które rozpoczyna się w oknie czatu, nie jest propagowane.
Scenariusz nakładki na stronie
Innym wariantem scenariusza „podwijania” jest sytuacja, gdy widzisz treści przewijane za nakładką w stałym położeniu. Zdecydowanie warto skorzystać z promocji overscroll-behavior
. Przeglądarka próbuje być pomocna, ale w efekcie sprawia, że strona wygląda na pełną błędów.
Przykład – tryb modalny z parametrem overscroll-behavior: contain
i bez niego:
Wyłączanie funkcji pociągnięcia w dół, aby odświeżyć
Wyłączenie działania „przeciągnij, aby odświeżyć” to pojedyncza linijka kodu CSS. Wystarczy, że zablokujesz łańcuch przewijania w całym elemencie definiującym obszar widoku. W większości przypadków jest to:
<html>
lub <body>
:
body {
/* Disables pull-to-refresh but allows overscroll glow effects. */
overscroll-behavior-y: contain;
}
Dzięki temu rozwiązaniu poprawiamy podwójne animacje „przeciągnij, aby odświeżyć” w prezentacji pola czatu i możemy zamiast tego zaimplementować niestandardowy efekt, który zapewnia płynniejszą animację wczytywania. Cała skrzynka odbiorcza jest też rozmyta podczas odświeżania:
Oto fragment pełnego kodu:
<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>
Wyłączanie efektu poświaty i efektu gumki podczas przewijania
Aby wyłączyć efekt odbicia po dotarciu do granicy przewijania, użyj polecenia overscroll-behavior-y: none
:
body {
/* Disables pull-to-refresh and overscroll glow effect.
Still keeps swipe navigations. */
overscroll-behavior-y: none;
}
Pełna wersja demonstracyjna
W całości demo czatu wykorzystuje element overscroll-behavior
do tworzenia niestandardowej animacji odświeżania po przeciągnięciu oraz blokuje przewijanie poza widget czatu. Dzięki temu użytkownicy będą mieli optymalne wrażenia, których trudno byłoby osiągnąć bez CSS.overscroll-behavior