Запретить прокрутку переполнения / резиновой ленты на iOS

Есть несколько вопросов по теме прокрутки переполнения / резиновой ленты на SO, но

  1. ни одно из них не обеспечивает решение, работающее во всех случаях на iOS 9.3.2
  2. ни одна из них не дает обширной и полной информации о самой проблеме

поэтому я создал этот пост как совокупность знаний.


Проблема:

То, о чем никогда не упоминалось ни в одном другом сообщении, заключается в том, что прокрутка переполнения iOS на самом деле является двухчастным поведением.

1. Прокрутка содержимого overflow: auto/scroll с помощью overflow: auto/scroll

Это общеизвестное и в основном желаемое поведение элемента с -webkit-overflow-scrolling: touch где непрерывное / импульсное поведение прокрутки проходит мимо контейнера элементов, чтобы замедлить прокручиваемое содержимое вниз плавно.

Это происходит, когда вы прокручиваете содержимое элемента с импульсом, достаточно высоким для прокрутки импульса, чтобы пройти мимо длины прокрученного содержимого.

При таком поведении свойство element.scrollTop изменяется соответственно на позицию прокрутки элементов и составляет менее 0 или больше максимальной прокрутки ( element.scrollHeight - element.offsetHeight ).

2. Прокрутка переполнения

Такое поведение возникает, если вы попытаетесь прокрутить любой элемент уже в минимальном / максимальном положении прокрутки даже дальше этого (элемент сверху вверх или элемент внизу вниз). Затем свиток, кажется, «пузырится» до и весь видовой экран прокручивается.

В противоположность выше здесь свойство element.scrollTop не изменяется, а вместо этого изменяются document.body.scrollTop .

Блокировка фокуса и переключение между режимами (задержка 1,5 с)

Наиболее раздражающим в этом контексте является то, что переключатель между двумя описанными выше типами не переключается мгновенно.

После ввода одного из них вы не можете переключать фокус на любой другой элемент (прокручиваемые элементы, кнопки, ссылки и т. Д.), И поэтому поведение прокрутки также не изменяется.

Например: если вы прокручиваете элемент, уже находящийся в верхней позиции вверх, вы вводите overflow scrolling type 2 и наиболее естественной реакцией для пользователя является попытка прокрутки назад. Поскольку фокус заблокирован для прокрутки тела, а не для overflow scrolling type 1 он остается в type 2 и все тело прокручивается вниз. Затем типичный пользователь начинает произвольно прокручивать вверх и вниз часто, не вырываясь из type 2 .

Переключение фокуса и, таким образом, изменение поведения прокрутки происходит только после завершения анимации переполнения, и элемент стоит на месте (даже немного длиннее [около 0,5 с], чем это).

таким образом, возвращаясь к предыдущему примеру, правильная реакция пользователя заключалась бы в том, чтобы перестать касаться экрана около 1 с – 1,5 с, а затем попытаться снова прокрутить вниз.

Решение:

Тип 1:

Самое основное решение, предотвращающее прокрутку переполнения самого элемента, – это предотrotation дефолтов по событиям касания.

 document.body.addEventListener('touchmove', function(e) { e.preventDefault(); }); 

Однако этот метод отключает прокрутку собственных импульсов браузеров и, следовательно, не подходит для большинства приложений. Однако с некоторой доработкой (только для предотвращения прокрутки вверх или вниз прокрутки вниз …) этот метод устраняет большинство проблем. В этой записи SO можно найти множество возможных реализаций.

Тип 2:

Однако прокрутка переполнения на теле не предотвращается описанными выше способами.

Одним из возможных решений, которое представляется разумным, является предотrotation того, чтобы элемент находился в его верхнем или нижнем положении, как описано как наилучшее решение по указанному вопросу .

 anElement.addEventListener('touchstart', function( event ){ if( this.scrollTop === 0 ) { this.scrollTop += 1; } else if( this.scrollTop + this.offsetHeight >= this.scrollHeight ) { this.scrollTop -= 1; } } 

Однако это не помогло работать над iOS 9.3.2.

Тем не менее, что работа была задана, position: fixed на элементе чтобы предотвратить движение тела. Обратите внимание, однако, что это все еще не полностью останавливает type 2 , поэтому иногда вы не можете прокручивать / фокусировать любой элемент, потому что в фоновом режиме type2 с блокировкой фокуса все еще происходит (опять же, когда вы перестаете касаться экрана на мгновение он снова работает так, как ожидалось).

Хотя это еще далеко не оптимальное решение, кажется, это лучшее, что мы можем получить за время, говорящее.

Изменить: Обратите внимание, что я не уверен, безопасно ли поставить position: fixed на элементе . Чтобы отслеживать возможные проблемы, которые я создал после публикации SO . По-видимому, было бы лучше создать элемент оболочки как дочерний элемент тела и установить этот элемент в position: fixed чтобы избежать проблем с масштабированием.


Изменить 2: Определенное решение

Скрипт iNoBounce творит чудеса. Просто загрузите его на страницу и получите веб-приложение без отскока. До сих пор я не нашел никаких проблем с этим решением.