Моля, имай предвид, че тази публикация е от юни 2015 г. и може част от информацията вече да е остаряла. Ще я актуализирам, когато имам време.
- Моята тестова страница
- Разбиране на поведението по подразбиране
- Разбирането на това какво прави CSS правилото „-webkit-overflow-scrolling“
- Потребителят трябва да изчака, докато приключи ефектът на гумения ластик
- Как да предотвратим превъртането на фонова страница
- Как да предотвратим прекомерното превъртане към фоновата страница.
- Как да предотвратим превъртането към фоновата страница
- Целият изходен код на страницата
За да оправя наскоро възникналия проблем със скролването в Safari на iOS, принудих се да създам собствена проста тестова страница и след това да използвам цялата налична информация и различните комбинации, които успях да намеря в интернет, за да опитам да разреша проблема.
По-долу е кратък преглед на това, което открих по време на този процес.
Моята тестова страница
Моята тестова страница беше доста проста. Тя се състоеше от примерни данни в статичен div, за да представлява «страницата», заедно с фиксиран div, който представлява надслойеното «меню» над страницата, както е показано.
Пълният изходен код на страницата можете да намерите в долната част на този блог пост.
Разбиране на поведението по подразбиране
Първото нещо, което направих, беше да се опитам да разбера какво е стандартното поведение на 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">
По принцип това работи, но по-обстойното тестване показва, че фонова страница все още понякога може да се превърта, когато достигнете най-горната или най-долната част на менюто.
Как да предотвратим прекомерното превъртане към фоновата страница.
Като приложите тази поправка, става възможно да се избегне „overscrolling“. Това означава, че когато даден елемент е превъртан до най-горния или най-долния му край, превъртането не продължава в тялото на страницата.
В резултат на това страницата не може да се превърта, което също предотвратява появата на ефекта на гумения ластик.
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 пиксел разстояние.
Ако превъртането никога не достига абсолютния горен край или абсолютния долен край, overscrolling не може да се случи.
Как да предотвратим превъртането към фоновата страница
Ако искате да премахнете ефекта на опъване от менюто - било заради естетика или защото, както при мен, той предизвиква допълнителни проблеми с рендирането - просто премахнете 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>