Мы знаем, что скорость реагирования на прокрутку имеет решающее значение для взаимодействия пользователя с веб-сайтом на мобильных устройствах, однако прослушиватели событий касания часто вызывают серьезные проблемы с производительностью прокрутки. Chrome решает эту проблему, позволяя прослушивателям событий касания быть пассивными (передавая параметр {passive: true}
в addEventListener()
) и предоставляя API событий указателя . Это отличные функции для внедрения нового контента в модели, не блокирующие прокрутку, но разработчикам иногда бывает трудно понять и внедрить их.
Мы считаем, что Интернет по умолчанию должен быть быстрым, и разработчикам не нужно разбираться в загадочных деталях поведения браузера. В Chrome 56 мы по умолчанию устанавливаем пассивные прослушиватели касаний в тех случаях, когда это чаще всего соответствует намерению разработчика. Мы считаем, что, сделав это, мы сможем значительно улучшить взаимодействие с пользователем, оказывая при этом минимальное негативное влияние на сайты.
В редких случаях это изменение может привести к непреднамеренной прокрутке. Обычно эту проблему легко решить, применив стиль touch-action : none к элементу, где прокрутка происходить не должна. Читайте дальше, чтобы узнать, как узнать, пострадали ли вы, и что вы можете с этим поделать.
Предыстория: Отменяемые события замедляют работу вашей страницы.
Если вы вызовете метод предотвращения Default() в событиях touchstart
или first touchmove
, вы предотвратите прокрутку. Проблема в том, что чаще всего слушатели не будут вызывать preventDefault()
, но браузеру необходимо дождаться завершения события, чтобы быть в этом уверенным. Определенные разработчиком «пассивные прослушиватели событий» решают эту проблему. Когда вы добавляете событие касания с объектом {passive: true}
в качестве третьего параметра в обработчике событий, вы сообщаете браузеру, что прослушиватель touchstart
не будет вызывать preventDefault()
, и браузер может безопасно выполнять прокрутку без блокировки слушатель. Например:
window.addEventListener("touchstart", func, {passive: true} );
Вмешательство
Наша основная мотивация — сократить время, необходимое для обновления дисплея после того, как пользователь коснулся экрана. Чтобы понять, как используются Touchstart и TouchMove, мы добавили метрики, позволяющие определить, как часто происходит блокировка прокрутки.
Мы изучили процент отменяемых событий касания, которые были отправлены корневому целевому объекту (окну, документу или телу), и определили, что около 80% этих прослушивателей концептуально пассивны, но не были зарегистрированы как таковые. Учитывая масштаб этой проблемы, мы заметили прекрасную возможность улучшить прокрутку без каких-либо действий разработчика, сделав эти события автоматически «пассивными».
Это побудило нас определить наше вмешательство следующим образом: если целью прослушивателя touchstart или touchmove является window
, document
или body
, мы по умолчанию passive
со значением true
. Это означает, что код типа:
window.addEventListener("touchstart", func);
становится эквивалентным:
window.addEventListener("touchstart", func, {passive: true} );
Теперь вызовы preventDefault()
внутри прослушивателя будут игнорироваться.
На графике ниже показано время, затраченное 1% верхних прокруток с момента, когда пользователь касается экрана для прокрутки, до момента обновления дисплея. Эти данные относятся ко всем веб-сайтам в Chrome для Android. До того, как вмешательство было включено, 1% прокруток занимал чуть более 400 мс. В бета-версии Chrome 56 это время сократилось до чуть более 250 мс; снижение примерно на 38%. В будущем мы надеемся сделать пассивное значение true по умолчанию для всех прослушивателей touchstart
и touchmove
, уменьшив это значение до уровня ниже 50 мс.

Поломка и руководство
В подавляющем большинстве случаев поломок не будет. Но когда поломка все же происходит, наиболее распространенным симптомом является то, что прокрутка происходит тогда, когда вы этого не хотите. В редких случаях разработчики также могут заметить неожиданные события щелчка (когда в touchend
прослушивателе отсутствовала preventDefault()
).
В Chrome 56 и более поздних версиях DevTools регистрирует предупреждение при вызове preventDefault()
в событии, когда вмешательство активно.
touch-passive.html:19 Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080
Ваше приложение может определить, может ли оно сталкиваться с этим в реальных условиях, проверив, оказал ли вызов preventDefault
какой-либо эффект через свойство defaultPrevented
.
Мы обнаружили, что подавляющее большинство затронутых страниц относительно легко исправить, если по возможности применить свойство CSS сенсорного действия . Если вы хотите запретить прокрутку и масштабирование в браузере внутри элемента, примените к нему touch-action: none
. Если у вас есть горизонтальная карусель, рассмотрите возможность применения к ней touch-action: pan-y pinch-zoom
чтобы пользователь мог по-прежнему прокручивать по вертикали и масштабировать как обычно. Правильное применение сенсорного действия уже необходимо в таких браузерах, как Edge для настольных компьютеров, которые поддерживают события указателя, а не события касания. Для мобильных Safari и более старых мобильных браузеров, которые не поддерживают сенсорное действие, ваши сенсорные прослушиватели должны продолжать вызывать preventDefault
даже если Chrome будет его игнорировать.
В более сложных случаях может потребоваться также полагаться на одно из следующих действий:
- Если ваш прослушиватель
touchstart
вызываетpreventDefault()
, убедитесь, что метод предотвращения Default() также вызывается из связанных прослушивателей сенсорного экрана, чтобы продолжать подавлять генерацию событий щелчка и другое поведение касания по умолчанию. - Последним (и не рекомендуется) передать
{passive: false}
в addEventListener(), чтобы переопределить поведение по умолчанию. Имейте в виду, что вам нужно будет определить, поддерживает ли пользовательский агент EventListenerOptions .
Заключение
В Chrome 56 прокрутка на многих веб-сайтах начинается значительно быстрее. Это единственное влияние, которое заметит большинство разработчиков в результате этого изменения. В некоторых случаях разработчики могут заметить непреднамеренную прокрутку.
Хотя это по-прежнему необходимо для мобильного Safari, веб-сайты не должны полагаться на вызов preventDefault()
внутри прослушивателей touchstart
и touchmove
поскольку больше не гарантируется, что это будет соблюдаться в Chrome. Разработчикам следует применять свойство CSS touch-action
к элементам, где прокрутка и масштабирование должны быть отключены, чтобы уведомлять браузер перед возникновением каких-либо событий касания. Чтобы подавить поведение касания по умолчанию (например, генерацию события щелчка), вызовите preventDefault()
внутри прослушивателя touchend
.