Aquesta entrada es va publicar el juny de 2015; potser alguna informació ja hagi quedat enrere. No sempre puc revisar-ho tot, però segueix sent interessant!
- La meva pàgina de proves
- Comprendre el comportament per defecte
- Comprendre què fa la propietat CSS "-webkit-overflow-scrolling"
- L'usuari ha d'esperar fins que s'acabi l'efecte de goma elàstica.
- Com evitar que la pàgina en segon pla faci scroll
- Com evitar que la pàgina en segon pla es desplaci.
- Com evitar el desplaçament excessiu cap a la pàgina en segon pla
- Codi font de tota la pàgina
Per resoldre un problema recent de desplaçament a Safari en iOS, vaig haver de crear la meva pròpia pàgina de proves senzilla i, després, aplicar tota la informació i les combinacions que vaig poder trobar a Internet per intentar resoldre el problema.
A continuació, trobaràs un breu resum de tot el que he descobert durant aquest procés.
La meva pàgina de proves
La meva pàgina de proves era bastant senzilla. Consistia en dades simulades en un element div estàtic per representar la 'pàgina', i, a més, un div fix que representava un 'menú' superposat sobre la pàgina, així.
El codi font complet de la pàgina es pot trobar al final d'aquest article del blog.
Comprendre el comportament per defecte
La primera cosa que vaig fer va ser intentar entendre el comportament per defecte de Safari en iOS. L'observació més destacada va ser que, quan desplacaves fins al final del menú, el cos de la pàgina mostrava un efecte d'estirament elàstic — una característica codificada directament a Safari.
Va passar el mateix quan vaig fer scroll fins a la part superior del menú.
Tanmateix, el primer problema que vaig notar va ser que si desplacaves contínuament fins al cim o al fons, Safari començava a mostrar fallades de renderització tant a la pàgina de fons com al menú.
No estic segur de per què, però sospito que té alguna cosa a veure amb l'efecte de goma elàstica.
Comprendre què fa la propietat CSS "-webkit-overflow-scrolling"
El següent pas que vaig fer va ser aplicar la regla CSS -webkit-overflow-scrolling al menú, que permet el desplaçament amb inèrcia.
Com es veu a la imatge de més avall, el desplaçament continua fins i tot després de desplaçar-me amb el dit.
Però també s'afegeix un efecte de goma quan s'arriba a la part superior o inferior, com es mostra a continuació.
L'usuari ha d'esperar fins que s'acabi l'efecte de goma elàstica.
Durant les meves proves, també vaig observar que, mentre l'efecte elàstic està en curs, l'usuari no pot canviar el focus a un altre element fins que l'animació s'hagi completada.
En l’exemple següent, primer desplaço la pàgina de fons i, a continuació, intento desplaçar ràpidament el menú, però acabo desplaçant la pàgina de fons en lloc d’això.
Tanmateix, si espero un moment que l’efecte acabi, ja podré començar a desplaçar-me pel menú.
Com evitar que la pàgina en segon pla faci scroll
Durant les meves proves, també vaig observar que, mentre l'efecte de goma elàstica està en curs, l'usuari no pot desviar el focus cap a un altre element fins que l'animació estigui completament finalitzada.
Basat en aquesta resposta de Stack Overflow, podeu assegurar que els elements amb disable-scrolling no executin la seva acció de desplaçament per defecte quan s'activa l'esdeveniment touchmove.
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();
}
};
I després aplica la classe disable-scrolling al div de la pàgina:
<div class="page disable-scrolling">
Aquest tipus funciona, però proves més extenses demostren que la pàgina de fons encara pot desplaçar-se de tant en tant quan arribes a la part superior o inferior del menú.
Com evitar que la pàgina en segon pla es desplaci.
Aplicant aquesta solució, és possible evitar el desbordament. Això implica que quan un element arriba a la part superior o inferior, el desplaçament no continua dins del cos de la pàgina.
Com a resultat, s'evita el desplaçament del cos de la pàgina, i això també evita que aparegui l'efecte de goma.
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"));
Aquest fragment de JavaScript evita que l'element arribi mai a la part superior ni a la part inferior, mantenint-lo a només 1 píxel de distància.
Si la posició de desplaçament mai no arriba al límit superior ni al límit inferior, l'excés de desplaçament no pot passar.
Com evitar el desplaçament excessiu cap a la pàgina en segon pla
Si vols eliminar l'efecte de goma del menú, sigui per motius estètics o perquè, com en el meu cas, va provocar problemes addicionals de renderització, elimina simplement la regla CSS -webkit-overflow-scrolling.
No obstant això, com podeu veure a continuació, també perdeu la inèrcia del desplaçament suau.
Codi font de tota la pàgina
Aquí teniu el codi font complet de la pàgina.
<!-- 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>