Λάβετε υπόψη ότι αυτή η ανάρτηση ιστολογίου δημοσιεύτηκε τον Ιούνιο του 2015, επομένως, ανάλογα με το πότε την διαβάζετε, ορισμένα σημεία ενδέχεται να είναι παρωχημένα. Δυστυχώς, δεν μπορώ πάντα να διατηρώ αυτές τις αναρτήσεις πλήρως ενημερωμένες για να διασφαλίσω ότι οι πληροφορίες παραμένουν ακριβείς.
- Η σελίδα δοκιμών μου
- Κατανόηση της προεπιλεγμένης συμπεριφοράς
- Κατανόηση του τι κάνει ο κανόνας CSS «-webkit-overflow-scrolling».
- Ο χρήστης πρέπει να περιμένει μέχρι να ολοκληρωθεί το εφέ ανάκρουσης
- Πώς να αποτρέψετε την κύλιση της σελίδας στο παρασκήνιο.
- Πώς να αποτρέψετε την κύλιση της σελίδας στο παρασκήνιο
- Πώς να αποτρέψετε το υπερβολικό κύλισμα προς τη σελίδα φόντου
- Ολόκληρος κώδικας πηγής της σελίδας
Για να διορθώσω ένα πρόσφατο πρόβλημα κύλισης στο Safari σε iOS, αναγκάστηκα να φτιάξω τη δική μου απλή σελίδα δοκιμών και στη συνέχεια να εφαρμόσω όλες τις πληροφορίες και τους συνδυασμούς που βρήκα στο διαδίκτυο, προκειμένου να προσπαθήσω να λύσω το ζήτημα.
Ακολουθεί μια σύντομη επισκόπηση όσων ανακάλυψα κατά τη διάρκεια αυτής της διαδικασίας.
Η σελίδα δοκιμών μου
Η σελίδα δοκιμών μου ήταν αρκετά βασική. Αποτελούταν από δοκιμαστικά δεδομένα σε ένα στατικό div που απεικόνιζε τη «σελίδα», μαζί με ένα σταθερό div που βρισκόταν πάνω από τη σελίδα και απεικόνιζε ένα επικαλυπτόμενο «μενού», όπως φαίνεται.
Ο πλήρης κώδικας πηγής της σελίδας βρίσκεται στο τέλος αυτού του άρθρου στο blog.
Κατανόηση της προεπιλεγμένης συμπεριφοράς
Το πρώτο πράγμα που έκανα ήταν να προσπαθήσω να καταλάβω τη βασική συμπεριφορά του Safari στο iOS. Η πιο αξιοσημείωτη παρατήρηση ήταν ότι όταν κύλιζες μέχρι το τέλος του μενού, το σώμα της σελίδας εμφάνιζε ένα «εφέ λάστιχου» — ένα χαρακτηριστικό που έχει προγραμματιστεί εξ αρχής στον Safari.
Το ίδιο συνέβη όταν κάνατε κύλιση μέχρι την κορυφή του μενού.
Ωστόσο, το πρώτο πρόβλημα που παρατήρησα είναι ότι, εάν συνεχίσετε να κυλάτε προς την κορυφή ή προς το κάτω μέρος της σελίδας, το Safari αρχίζει να παρουσιάζει προβλήματα απεικόνισης τόσο στο φόντο της σελίδας όσο και στο μενού.
Δεν είμαι σίγουρος γιατί, αλλά υποπτεύομαι ότι έχει σχέση με το εφέ ελαστικού.
Κατανόηση του τι κάνει ο κανόνας CSS «-webkit-overflow-scrolling».
Το επόμενο βήμα που έκανα ήταν να εφαρμόσω τον κανόνα CSS -webkit-overflow-scrolling στο μενού, ο οποίος ενεργοποιεί την κύλιση με ορμή.
Όπως φαίνεται στην εικόνα παρακάτω, η κύλιση συνεχίζεται ακόμη και αφού σύρω το δάχτυλό μου.
Αλλά προσθέτει επίσης ένα εφέ ελαστικής κίνησης όταν κάνετε κύλιση μέχρι την κορυφή ή το τέλος, όπως φαίνεται παρακάτω.
Ο χρήστης πρέπει να περιμένει μέχρι να ολοκληρωθεί το εφέ ανάκρουσης
Κατά τη διάρκεια των δοκιμών μου, παρατήρησα επίσης ότι ενώ βρίσκεται σε εξέλιξη το εφέ ελαστικού, ο χρήστης δεν μπορεί να μεταφέρει την εστίαση σε άλλο στοιχείο μέχρι να ολοκληρωθεί πλήρως η κίνηση.
Στο παράδειγμα που ακολουθεί, αρχικά κυλάω τη σελίδα στο φόντο και μετά προσπαθώ γρήγορα να κυλήσω το μενού, αλλά τελικά συνεχίζω να κυλάω τη σελίδα στο φόντο.
Ωστόσο, αν περιμένω λίγο μέχρι να ολοκληρωθεί το εφέ, τότε μπορώ να αρχίσω να κυλίσω το μενού.
Πώς να αποτρέψετε την κύλιση της σελίδας στο παρασκήνιο.
Κατά τη διάρκεια των δοκιμών μου, διαπίστωσα επίσης ότι καθώς το εφέ ελαστικής έκτασης βρίσκεται σε εξέλιξη, ο χρήστης δεν μπορεί να μεταβεί σε άλλο στοιχείο μέχρι να ολοκληρωθεί πλήρως η κίνηση.
Με βάση αυτήν την απάντηση από το Stack Overflow, μπορείτε να διασφαλίσετε ότι τα στοιχεία με το disable-scrolling δεν θα εκτελούν την προεπιλεγμένη ενέργεια κύλισης όταν ενεργοποιείται το γεγονός 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();
}
};
Και στη συνέχεια εφαρμόστε την κλάση disable-scrolling στο div της σελίδας:
<div class="page disable-scrolling">
Κάπως λειτουργεί, αλλά οι πιο εκτεταμένες δοκιμές δείχνουν ότι η σελίδα υποβάθρου μπορεί ακόμη μερικές φορές να κυλίσει όταν φτάνετε στην κορυφή ή στην κάτω άκρη του μενού.
Πώς να αποτρέψετε την κύλιση της σελίδας στο παρασκήνιο
Με την εφαρμογή αυτής της διόρθωση, καθίσταται δυνατή η αποτροπή της «υπερκύλισης». Αυτό σημαίνει ότι όταν ένα στοιχείο έχει μετακινηθεί μέχρι την απόλυτη κορυφή ή το κάτω άκρο του, η κύλιση δεν συνεχίζεται μέσα στο σώμα της σελίδας.
Ως αποτέλεσμα, εμποδίζεται η κύλιση της σελίδας, οπότε αποτρέπεται και το φαινόμενο της ελαστικής κίνησης (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"));
Αυτό το απόσπασμα JavaScript αποτρέπει το στοιχείο από το να φτάσει ποτέ στην κορυφή ή στην κάτω άκρη, κρατώντας το μόλις 1 εικονοστοιχείο μακριά.
Αν η θέση κύλισης δεν φτάνει ποτέ στην απόλυτη κορυφή ή στο απόλυτο κάτω άκρο, η υπερκύλιση δεν μπορεί να συμβεί.
Πώς να αποτρέψετε το υπερβολικό κύλισμα προς τη σελίδα φόντου
Αν θέλετε να αφαιρέσετε το εφέ ελαστικής ανάδρασης από το μενού — είτε για αισθητικούς λόγους είτε, όπως στην περίπτωσή μου, επειδή προκάλεσε επιπλέον προβλήματα απόδοσης — απλώς αφαιρέστε τον κανόνα CSS -webkit-overflow-scrolling.
Ωστόσο, όπως φαίνεται παρακάτω, χάνετε επίσης τη δυναμική της ομαλής κύλισης.
Ολόκληρος κώδικας πηγής της σελίδας
Ο πλήρης κώδικας πηγής της σελίδας βρίσκεται παρακάτω.
<!-- 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>