Houd er rekening mee dat deze blogpost in juni 2015 is gepubliceerd. Afhankelijk van wanneer u hem leest, kunnen bepaalde delen dus verouderd zijn. Helaas kan ik deze berichten niet altijd volledig up-to-date houden om ervoor te zorgen dat de informatie accuraat blijft.
- Mijn testpagina
- Het standaardgedrag begrijpen
- Begrijpen wat de CSS-regel '-webkit-overflow-scrolling' doet
- De gebruiker moet wachten totdat het rubberband-effect is afgelopen.
- Hoe voorkom je dat de achtergrondpagina scrollt
- Hoe voorkom je overmatig scrollen naar de achtergrondpagina
- Hoe voorkom je dat je naar de achtergrondpagina scrolt
- Volledige broncode van de pagina
Om een recent scrollprobleem in Safari op iOS op te lossen, moest ik mijn eigen eenvoudige testpagina maken en vervolgens alle informatie en combinaties die ik op internet kon vinden toepassen om te proberen het probleem op te lossen.
Hieronder vindt u een beknopt overzicht van wat ik tijdens dit proces heb ontdekt.
Mijn testpagina
Mijn testpagina was vrij eenvoudig. Het bestond uit voorbeeldgegevens in een statische div om de 'pagina' voor te stellen, samen met een vaste div die een overlay-menu boven de pagina laat zien, zoals dit.
De volledige broncode van de pagina is onderaan dit blogbericht te vinden.
Het standaardgedrag begrijpen
Het eerste wat ik deed, was proberen het standaardgedrag van Safari op iOS te begrijpen. De meest opvallende waarneming was dat wanneer je helemaal naar de onderkant van het menu scrolt, de body van de pagina een rubberband-effect vertoonde — een vast ingebouwde eigenschap in Safari.
Hetzelfde gebeurde toen je naar de bovenkant van het menu scrollde.
Het eerste probleem dat me opviel, was dat Safari weergaveproblemen begon te vertonen wanneer je voortdurend helemaal naar boven of helemaal naar beneden scrolt, in zowel de achtergrondpagina als het menu.
Ik weet niet zeker waarom, maar ik vermoed dat het te maken heeft met de rubberbandfunctie.
Begrijpen wat de CSS-regel '-webkit-overflow-scrolling' doet
Het volgende wat ik deed, was de -webkit-overflow-scrolling CSS-regel toe te passen op het menu, wat momentum-gebaseerd scrollen mogelijk maakt.
Zoals in de onderstaande afbeelding te zien is, blijft het scrollen doorgaan, zelfs nadat ik met mijn vinger over het scherm veeg.
Maar het voegt ook een rubberband-gevoel toe wanneer je naar de allereerste positie bovenaan of onderaan scrolt, zoals hieronder weergegeven.
De gebruiker moet wachten totdat het rubberband-effect is afgelopen.
Tijdens mijn tests merkte ik ook op dat, terwijl het rubberband-effect gaande is, de gebruiker de focus niet naar een ander element kan verplaatsen totdat de animatie volledig is voltooid.
In het onderstaande voorbeeld scroll ik eerst de achtergrondpagina en probeer daarna snel het menu te scrollen, maar uiteindelijk blijf ik toch de achtergrondpagina scrollen.
Echter, als ik even wacht tot het effect is afgelopen, kan ik daarna door het menu scrollen.
Hoe voorkom je dat de achtergrondpagina scrollt
Tijdens mijn tests merkte ik ook op dat het rubberband-effect gaande is en dat de gebruiker de focus niet naar een ander element kan verschuiven totdat de animatie volledig is afgelopen.
Gebaseerd op dit antwoord van Stack Overflow, kun je ervoor zorgen dat elementen met disable-scrolling niet hun standaard scrollactie uitvoeren wanneer het touchmove evenement wordt geactiveerd.
document.ontouchmove = function(event) {
var isTouchMoveAllowed = true,
target = event.target;
while (target !== null) {
if (target.classList && target.classList.contains('disable-scrolling')) {
isTouchMoveAllowed = false;
break;
}
target = target.parentNode;
}
if (!isTouchMoveAllowed) {
event.preventDefault();
}
};
En pas vervolgens de klasse disable-scrolling toe op de pagina-div:
<div class="page disable-scrolling">
Dit werkt wel redelijk, maar bij uitgebreide tests blijkt dat de achtergrondpagina soms nog kan scrollen wanneer je de boven- of onderkant van het menu bereikt.
Hoe voorkom je overmatig scrollen naar de achtergrondpagina
Door deze fix toe te passen, wordt overscroll voorkomen. Dit betekent dat wanneer een element helemaal naar de top of de onderkant is gescrold, het scrollen niet verder gaat in de body.
Als gevolg hiervan kan de pagina niet meer scrollen, waardoor ook het rubberband-effect niet optreedt.
function removeIOSRubberEffect(element) {
element.addEventListener("touchstart", function() {
var top = element.scrollTop,
totalScroll = element.scrollHeight,
currentScroll = top + element.offsetHeight;
if (top === 0) {
element.scrollTop = 1;
} else if (currentScroll === totalScroll) {
element.scrollTop = top - 1;
}
});
}
removeIOSRubberEffect(document.querySelector(".scrollable"));
Wat deze JavaScript-snippet doet, is voorkomen dat het element ooit tegen de bovenkant of onderkant aankomt door het op slechts 1 pixel afstand te houden.
Als de scrollpositie nooit de absolute bovenkant of onderkant bereikt, kan overscrollen nooit plaatsvinden.
Hoe voorkom je dat je naar de achtergrondpagina scrolt
Als je het rubberband-effect van het menu wilt verwijderen—hetzij om esthetische redenen, of omdat het, zoals in mijn geval, extra weergaveproblemen veroorzaakte—verwijder dan eenvoudig de CSS-regel -webkit-overflow-scrolling.
Maar zoals hieronder te zien is, verlies je ook de vloeiende scroll-ervaring.
Volledige broncode van de pagina
Hier is de volledige broncode van de pagina.
<!-- License MIT, Author Special Agent Squeaky (specialagentsqueaky.com) --> <!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="minimum-scale=1.0, width=device-width, maximum-scale=1.0, user-scalable=no, initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style> .page{ font-size: 24px; overflow: scroll; } .menu{ position: fixed; top: 0; bottom: 0; left: 0; width: 80%; background: gray; z-index: 1; font-size: 10px; overflow: scroll; /* uncomment to get smooth momentum scroll, but also a rubber band effect */ /*-webkit-overflow-scrolling: touch;*/ } .menu-item{ padding: 10px; background: darkgray; font-size: 24px; } </style>
</head>
<body>
<div class="menu scrollable">
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
</div>
<div class="page disable-scrolling">
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,
when an unknown printer took a galley of type and scrambled it to make a type
specimen book. It has survived not only five centuries, but also the leap into
electronic typesetting, remaining essentially unchanged. It was popularised in
the 1960s with the release of Letraset sheets containing Lorem Ipsum passages,
and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
</div>
<script>
document.ontouchmove = function(event) {
var isTouchMoveAllowed = true,
target = event.target;
while (target !== null) {
if (target.classList && target.classList.contains('disable-scrolling')) {
isTouchMoveAllowed = false;
break;
}
target = target.parentNode;
}
if (!isTouchMoveAllowed) {
event.preventDefault();
}
};
function removeIOSRubberEffect(element) {
element.addEventListener("touchstart", function() {
var top = element.scrollTop,
totalScroll = element.scrollHeight,
currentScroll = top + element.offsetHeight;
if (top === 0) {
element.scrollTop = 1;
} else if (currentScroll === totalScroll) {
element.scrollTop = top - 1;
}
});
}
removeIOSRubberEffect(document.querySelector(".scrollable"));
</script>
</body>
</html>