Зверніть увагу, що цей допис у блозі було опубліковано в червні 2015 року, тому залежно від того, коли ви його читаєте, деякі його частини можуть бути застарілими. На жаль, я не завжди можу повністю оновлювати ці дописи, щоб забезпечити точність інформації.
- Моя тестова сторінка
- Розуміння поведінки за замовчуванням
- Розуміння того, як працює CSS-правило «-webkit-overflow-scrolling»
- Please wait for the rubber-band effect to finish.
- Як запобігти прокручуванню фонової сторінки
- Як запобігти надмірному прокручуванню до фонової сторінки
- Як запобігти перепрокручуванню до фонової сторінки
- Повний вихідний код сторінки
Щоб виправити нещодавню проблему з прокручуванням у Safari на iOS, мені довелося створити власну просту тестову сторінку, а потім застосувати всю інформацію та різноманітні комбінації, які я міг знайти в Інтернеті, щоб спробувати вирішити проблему.
Нижче наведено стислий огляд того, що мені вдалося з'ясувати під час цього процесу.
Моя тестова сторінка
Моя тестова сторінка була досить простою. Вона складалася з тестових даних у статичному div-елементі, щоб уявити «сторінку», разом із фіксованим div-елементом, який зображає накладене «меню» над сторінкою, ось так.
Повний вихідний код цієї сторінки можна знайти внизу цього допису в блозі.
Розуміння поведінки за замовчуванням
Перше, що я зробив, — це спробував зрозуміти стандартну поведінку Safari на iOS. Найпомітнішим було те, що коли ви прокручували сторінку до самого дна меню, тіло сторінки демонструвало «ефект гумової стрічки» — жорстко закодована функція в Safari.
Так само сталося, коли прокручували до самого верху меню.
Однак першою проблемою, яку я помітив, було те, що якщо ви постійно прокручуєте до самого верху або низу, Safari починає створювати артефакти відображення як на фоновій сторінці, так і в меню.
Я не зовсім розумію, чому так, але думаю, що це має щось спільне з функцією еластичної прокрутки.
Розуміння того, як працює CSS-правило «-webkit-overflow-scrolling»
Наступним кроком стало застосування правила CSS -webkit-overflow-scrolling до меню, що забезпечує інерційне прокручування.
Як показано на зображенні нижче, прокручування продовжується навіть після того, як я провів пальцем.
До того ж під час прокручування до самого верхнього або нижнього краю з'являється ефект гумової стрічки, як показано нижче.
Please wait for the rubber-band effect to finish.
Під час тестування я також помітив, що під час виконання ефекту відскоку користувач не може переключити фокус на інший елемент, доки анімація повністю не завершиться.
У наведеному нижче прикладі спочатку прокручую фонову сторінку, а потім швидко намагаюся прокрутити меню, але в підсумку продовжую прокручувати саме фонову сторінку.
Однак, якщо я трохи зачекаю, поки ефект закінчиться, зможу почати прокручувати меню.
Як запобігти прокручуванню фонової сторінки
Під час тестування я також помітив, що поки триває еластичний ефект відскоку, користувач не може перемістити фокус на інший елемент, доки анімація повністю не завершиться.
Згідно з цією відповіддю від 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();
}
};
І потім застосуйте до елемента div сторінки клас disable-scrolling:
<div class="page disable-scrolling">
Цей підхід працює частково, але більш ґрунтовне тестування показує, що фонова сторінка все ще іноді прокручується, коли ви досягаєте самого верху або дна меню.
Як запобігти надмірному прокручуванню до фонової сторінки
За допомогою цього виправлення fix, можна запобігати «оверскролінгу». Це означає, що коли елемент прокручується до самого верху або низу, прокручування не переходить далі до тіла документа.
У результаті сторінка не прокручується, що також запобігає виникненню ефекту пружного відскоку.
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 запобігає тому, щоб елемент дійшов до самого верху або самого низу, утримуючи його на відстані всього одного пікселя.
Якщо положення прокрутки ніколи не досягає абсолютної верхньої чи нижньої межі, перевищення прокрутки неможливе.
Як запобігти перепрокручуванню до фонової сторінки
Якщо хочете прибрати ефект гумки з меню — або з естетичних причин, або тому, що, як у моєму випадку, він викликав додаткові проблеми з відображенням, просто видаліть 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>