Vă rugăm să rețineți că această postare pe blog a fost publicată în iunie 2015, așa că, în funcție de momentul în care o citiți, este posibil ca anumite părți să fie învechite. Din păcate, nu pot menține întotdeauna aceste postări complet actualizate pentru a asigura acuratețea informațiilor.
- Pagina mea de testare
- Înțelegerea comportamentului implicit
- Înțelegerea efectului pe care îl are regula CSS "-webkit-overflow-scrolling"
- Utilizatorul trebuie să aștepte până la terminarea efectului Rubber-Band.
- Cum să împiedici derularea paginii din fundal
- Cum să previi derularea paginii din fundal
- Cum să eviți derularea către pagina de fundal
- Codul sursă al întregii pagini
Pentru a rezolva o problemă recentă de derulare în Safari pe iOS, am fost nevoit să creez o pagină de test simplă și apoi să aplic toate informațiile și combinațiile pe care le-am găsit pe internet pentru a încerca să rezolv problema.
Mai jos este o scurtă prezentare a ceea ce am descoperit în timpul acestui proces.
Pagina mea de testare
Pagina mea de test a fost destul de simplă. A fost alcătuită din date simulate într-un div static pentru a reprezenta pagina, împreună cu un div fix care reprezintă un „meniul” suprapus peste pagină, precum acesta.
Codul sursă complet al paginii poate fi găsit în partea de jos a acestui articol de pe blog.
Înțelegerea comportamentului implicit
Primul lucru pe care l-am făcut a fost să încerc să înțeleg comportamentul implicit al Safari pe iOS. Cea mai remarcabilă observație a fost că, atunci când derulezi până la capătul meniului, corpul paginii afișează un efect de bandă elastică - o funcționalitate încorporată în Safari.
La fel s-a întâmplat și când am ajuns în partea de sus a meniului.
Cu toate acestea, primul lucru pe care l-am observat a fost că, dacă derulezi în mod continuu până la capătul superior sau inferior, Safari începe să afișeze glitchuri de randare atât în pagina de fundal, cât și în meniul.
Nu sunt sigur de ce, dar bănuiesc că are legătură cu funcția de bandă elastică.
Înțelegerea efectului pe care îl are regula CSS "-webkit-overflow-scrolling"
Următorul lucru pe care l-am făcut a fost să aplic regula CSS -webkit-overflow-scrolling pentru meniul, ceea ce permite derare cu inerție.
După cum se poate vedea în imaginea de mai jos, derularea continuă chiar și după ce glisez cu degetul.
Dar adaugă și un efect de elasticitate atunci când derulezi până la partea superioară sau inferioară a paginii, așa cum se vede mai jos.
Utilizatorul trebuie să aștepte până la terminarea efectului Rubber-Band.
În timpul testelor mele, am observat, de asemenea, că în timpul rulării efectului elastic de tip rubber-band utilizatorul nu poate muta focalizarea către un alt element până la finalizarea completă a animației.
În exemplul de mai jos, derulez mai întâi pagina din fundal, apoi încerc rapid să derulez meniul, dar ajung să continui să derulez pagina din fundal.
Totuși, dacă aștept puțin până se termină efectul, pot apoi să încep să derulez meniul.
Cum să împiedici derularea paginii din fundal
În timpul testelor mele, am observat, de asemenea, că în timpul desfășurării efectului rubber-band, utilizatorul nu poate muta focalizarea către un alt element până la finalizarea completă a animației.
Pornind de la acest răspuns de pe Stack Overflow, poți să te asiguri că elementele cu disable-scrolling nu vor efectua acțiunea implicită de derulare atunci când este declanșat evenimentul 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 apoi aplică clasa disable-scrolling pe div-ul paginii:
<div class="page disable-scrolling">
Funcționează într-o oarecare măsură, dar teste mai ample arată că pagina de fundal poate totuși derula uneori când ajungi la partea superioară sau inferioară a meniului.
Cum să previi derularea paginii din fundal
Aplicând această soluție, devine posibil să preveniți derularea în exces. Aceasta înseamnă că, atunci când un element este derulat până la marginea sa superioară sau inferioară, derularea nu trece în continuare în corpul paginii.
Ca urmare, corpul nu se poate derula, iar acest lucru împiedică, de asemenea, apariția efectului rubber-band.
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"));
Ce face acest fragment JavaScript este să împiedice ca elementul să ajungă niciodată în partea de sus sau în partea de jos, păstrându-l la o distanță de doar 1 pixel.
Dacă poziția de derulare nu atinge niciodată partea superioară sau inferioară a documentului, depășirea derulării nu poate apărea.
Cum să eviți derularea către pagina de fundal
Dacă vrei să elimini efectul de elasticitate al meniului — fie din motive estetice, fie pentru că, în cazul meu, a cauzat glitchuri suplimentare de randare — pur și simplu elimină regula CSS -webkit-overflow-scrolling.
Cu toate acestea, așa cum poți vedea mai jos, pierzi și inerția derulării fluente.
Codul sursă al întregii pagini
Iată codul sursă complet al paginii.
<!-- 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>