In het kort
Met de css-property overscroll-behavior kunnen ontwikkelaars het standaard scrollgedrag van de browser overschrijven als de boven- of onderkant van de content wordt bereikt. Use cases zijn onder andere de functie Trek omlaag om te vernieuwen uitzetten op mobiele apparaten, de effecten van overscroll-gloed en rubberbanding verwijderen en voorkomen dat paginacontent scrollt als deze zich onder een modaal/overlay bevindt.
Achtergrond
Scrollgrenzen en scrollketens
Scrollen is een van de meest fundamentele manieren om interactie met een pagina te hebben, maar bepaalde UX-patronen kunnen lastig zijn vanwege het eigenzinnige standaardgedrag van de browser. Neem bijvoorbeeld een app-lade met een groot aantal items waar de gebruiker doorheen moet scrollen. Als ze de onderkant bereiken, stopt de overloopcontainer met scrollen omdat er geen content meer is om te consumeren. Met andere woorden: de gebruiker bereikt een scrollgrens. Maar let op wat er gebeurt als de gebruiker verder scrollt. De content achter de lade begint te scrollen. Scrollen wordt overgenomen door de bovenliggende container, in het voorbeeld de hoofdpagina zelf.
Dit gedrag wordt scroll chaining genoemd en is het standaardgedrag van de browser bij het scrollen door content. Vaak is de standaardinstelling prima, maar soms is deze niet wenselijk of zelfs onverwacht. Bepaalde apps willen misschien een andere gebruikerservaring bieden als de gebruiker een scrollgrens bereikt.
Het effect van trekken om te vernieuwen
Trek omlaag om te vernieuwen is een intuïtief gebaar dat populair is geworden door mobiele apps zoals Facebook en Twitter. Als je een social feed naar beneden trekt en loslaat, ontstaat er nieuwe ruimte om recentere posts te laden. Deze specifieke UX is zelfs zo populair geworden dat mobiele browsers zoals Chrome op Android hetzelfde effect hebben overgenomen. Als je bovenaan de pagina omlaag swipet, wordt de hele pagina vernieuwd:
bij het vernieuwen van een feed in hun PWA.
vernieuwt de hele pagina.
In situaties zoals de Twitter-PWA,
kan het zinvol zijn om de systeemeigen actie voor omlaag trekken om te vernieuwen uit te zetten. Waarom? In deze app wil je waarschijnlijk niet dat de gebruiker de pagina per ongeluk vernieuwt. Er is ook een kans dat je een dubbele vernieuwingsanimatie ziet. Het kan ook leuker zijn om de actie van de browser aan te passen, zodat deze beter aansluit bij de branding van de site. Het nadeel is dat dit type aanpassing lastig te realiseren is. Ontwikkelaars schrijven onnodige JavaScript, voegen niet-passieve touch-listeners toe (die scrollen blokkeren) of plaatsen de hele pagina in een 100vw/vh <div> (om te voorkomen dat de pagina overloopt). Deze tijdelijke oplossingen hebben
goed gedocumenteerde negatieve
effecten op de scrollprestaties.
Dat kunnen we beter!
Nieuw: overscroll-behavior
De overscroll-behavior -property is een nieuwe CSS-functie die bepaalt wat er gebeurt als je te ver scrollt in een container (waaronder de pagina zelf). Je kunt deze eigenschap gebruiken om scroll chaining te annuleren, de actie 'trekken om te vernieuwen' uit te zetten of aan te passen, rubberbanding-effecten op iOS uit te zetten (als Safari overscroll-behavior implementeert) en meer.
Het beste is dat het gebruik van overscroll-behavior geen negatieve invloed heeft op de paginaprestaties, zoals de hacks die in de inleiding worden genoemd.
De property heeft 3 mogelijke waarden:
- auto: Standaard. Scrollbewegingen die op het element beginnen, kunnen worden doorgegeven aan bovenliggende elementen.
- contain: voorkomt scrollketens. Scrollen wordt niet doorgegeven aan bovenliggende elementen,
maar lokale effecten binnen de node worden wel getoond. Bijvoorbeeld het overscroll-gloei-effect op Android of het rubberbanding-effect op iOS, dat de gebruiker laat weten wanneer deze een scrollgrens heeft bereikt. Opmerking: Als je
overscroll-behavior: containgebruikt voor het elementhtml, voorkom je navigatieacties voor overscrollen. - none: hetzelfde als
contain, maar voorkomt ook overscroll-effecten binnen de node zelf (bijvoorbeeld Android-overscroll-gloed of iOS-rubberbanding).
Laten we een paar voorbeelden doornemen om te zien hoe je overscroll-behavior gebruikt.
Voorkomen dat scrollen een element met een vaste positie verlaat
Het chatboxscenario
Overweeg een vastgezet chatvak onderaan de pagina. Het is de bedoeling dat de chatbox een op zichzelf staand component is en dat deze afzonderlijk van de content erachter scrollt. Maar door scroll chaining begint het document te scrollen zodra de gebruiker het laatste bericht in de chatgeschiedenis bereikt.
Voor deze app is het beter als scrolls die in de chatbox beginnen, in de chat blijven. We kunnen dit doen door overscroll-behavior: contain toe te voegen aan het element dat de chatberichten bevat:
#chat .msgs {
overflow: auto;
overscroll-behavior: contain;
height: 300px;
}
In wezen maken we een logische scheiding tussen de scrollcontext van de chatbox en de hoofdpagina. Het eindresultaat is dat de hoofdpagina blijft staan als de gebruiker de boven- of onderkant van de chatgeschiedenis bereikt. Scrollen dat begint in het chatvak, wordt niet doorgegeven.
Het scenario voor pagina-overlay
Een andere variant van het scenario 'underscroll' is wanneer u content ziet scrollen achter een overlay met vaste positie. Een weggevertje
overscroll-behavior is op zijn plaats. De browser probeert te helpen, maar
het zorgt ervoor dat de site er buggy uitziet.
Voorbeeld: modaal met en zonder overscroll-behavior: contain:
Trek omlaag om te vernieuwen uitzetten
Je kunt de actie 'trekken om te vernieuwen' uitzetten met één regel CSS. Voorkom gewoon scroll chaining op het hele element dat de viewport definieert. In de meeste gevallen is dat
<html> of <body>:
body {
/* Disables pull-to-refresh but allows overscroll glow effects. */
overscroll-behavior-y: contain;
}
Met deze eenvoudige toevoeging lossen we de dubbele animaties voor omlaag trekken om te vernieuwen op in de chatbox-demo. In plaats daarvan kunnen we een aangepast effect implementeren dat een nettere laadanimatie gebruikt. De hele inbox wordt ook wazig terwijl de inbox wordt vernieuwd:
Hier is een fragment van de volledige code:
<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>
Gloed bij overscrollen en rubberbanding-effecten uitzetten
Gebruik overscroll-behavior-y: none om het bounce-effect uit te zetten als je een scrollgrens bereikt:
body {
/* Disables pull-to-refresh and overscroll glow effect.
Still keeps swipe navigations. */
overscroll-behavior-y: none;
}
Volledige demo
In de volledige chatboxdemo wordt overscroll-behavior gebruikt om een aangepaste animatie voor omlaag trekken om te vernieuwen te maken en te voorkomen dat scrollen de chatboxwidget verlaat. Dit biedt een optimale gebruikerservaring die zonder CSS moeilijk te bereiken zou zijn geweest.
overscroll-behavior