Что такое скролл в браузере

Обновлено: 04.07.2024

Анимации, имеющие отношение к скроллингу веб-страниц, существуют уже многие годы. В последнее время подобные анимации стали распространённее. Возможно, дело тут отчасти в том, что устройства, используемые для работы в интернете, стали мощнее. Эти устройства способны нормально обрабатывать и выводить больше визуальных эффектов, чем раньше.

Существует множество технологий, связанных со скроллингом. Цель этой статьи заключается в том, чтобы дать обзор таких технологий и инструментов, которые помогут подобрать и создать то, что нужно в каждой конкретной ситуации. Я разделил бы технологии скроллинга на две широкие категории. В первую входят технологии для реализации специфических механизмов скроллинга, во вторую — технологии скроллинга общего назначения.

Технологии для реализации специфических механизмов скроллинга

В CSS существует несколько простых стандартных эффектов скроллинга, поддерживаемых современными браузерами. В некоторых случаях их применения может быть достаточно для того чтобы обеспечить особенные нужды некоего проекта.

▍CSS-свойство position: sticky

Если вам нужно, чтобы некий элемент не прокручивался бы вместе с остальным содержимым страницы, то при стилизации этого элемента достаточно применить свойство position: sticky . Это — простой и понятный приём, его поддержка встроена в современные браузеры. Но для того, чтобы это работало бы в IE и в некоторых мобильных браузерах, понадобится полифилл. Если вам интересна эта тема — взгляните на данный материал.


Синий элемент «упирается» в верхнюю часть контейнера и не прокручивается вместе с остальными элементами

Вот демонстрация такого скроллинга.

▍Эффект параллакса

Эффект параллакса — это, скорее, не особая технология, а специальный технический приём. Но, как бы там ни было, этот эффект может оказаться весьма кстати в тех случаях, когда нужно, чтобы при скроллинге разные части страницы двигались бы с разной скоростью. Данный приём хорошо описан в этом материале. Существует и немало примеров его реализации. Например — этот. Для меня главный минус этого приёма заключается в том, что сложно понять то, какие значения, дающие правильный эффект параллакса, нужно использовать для настройки перспективы и трансформаций.


Эффект параллакса: элементы движутся с разной скоростью.

Вот демонстрация эффекта параллакса.

▍Прокрутка с привязкой к определённым точкам

Использование скроллинга с точками привязки позволяет браузеру автоматически настраивать положение элементов, перемещая их в определённую позицию после того, как пользователь завершил обычную операцию скроллинга. Это может оказаться полезным в случаях, когда нужно, чтобы после завершения прокрутки некий элемент находился бы целиком в поле зрения пользователя. Однако соответствующий API пока ещё нестабилен, поэтому постарайтесь пользоваться самыми свежими его реализациями и с осторожностью относитесь к применению этого подхода к скроллингу в продакшне. Вот хорошая статья на эту тему.


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

Вот демонстрация работы скроллинга с точками привязки.

▍Плавная прокрутка

Плавный скроллинг поддерживается средствами браузера при прокрутке страницы до определённого раздела с использованием метода window.scrollTo() в JavaScript, или даже с применением CSS-свойства scroll-behavior. В настоящее время для реализации плавного скроллинга со сглаживанием движений колеса мыши требуются специальные JavaScript-библиотеки. Но при применении таких библиотек нужно обеспечить их нормальное взаимодействие с другими технологиями скроллинга. Кроме того, использование плавного скроллинга — это далеко не всегда хорошая идея.

Технологии скроллинга общего назначения

В настоящее время нет способа, применяя лишь CSS, запускать какие-либо анимации скроллинга общего назначения, основываясь на позиции прокрутки (хотя имеется предложение, в соответствии с которым в отдалённом будущем в нашем распоряжении могут появиться некие анимации, основанные на технологиях скроллинга общего назначения). В результате, если вы хотите анимировать элементы при скроллинге, вам нужно, как минимум, использовать некоторый объём JavaScript-кода для достижения требуемого эффекта. Существуют два метода применения JavaScript для анимирования элементов при скроллинге. Первый заключается в использовании API Intersection Observer, второй — в обработке события scroll .

▍Использование API Intersection Observer

API IntersectionObserver позволяет с успехом решать различные задачи, связанные со скроллингом, в том случае, если всё, что нужно для запуска анимации, — это знание о том, видим ли элемент в области просмотра, а так же о том, какая именно часть элемента видима. Это делает API IntersectionObserver отличным инструментом для запуска анимации, сопровождающей появление элемента на экране. Но, даже так, некоторые эффекты очень сложно (хотя и можно) реализовать с помощью этого API. Например — это запуск разных анимаций в зависимости от направления движения элемента. Этот API, кроме того, не особенно полезен в ситуации, если при скроллинге нужно запускать анимацию тогда, когда элемент находится где-то в середине области просмотра, то есть, не появляется в области просмотра и не исчезает из неё.

▍Использование события scroll

Перед тем, кто, для реализации анимации при скроллинге, использует событие scroll , открываются очень большие возможности. Этот приём позволяет, при прокрутке, воздействовать на элемент при любом положении элемента относительно границ области просмотра. Используя событие scroll , можно очень точно, в соответствии с нуждами проекта, задавать позиции начала и окончания анимации.

Учитывая это, нужно отметить, что данный подход к анимации скроллинга может создать немалую нагрузку на систему. Так происходит в том случае, если разработчик не заботится о производительности и не ограничивает частоту обработки события scroll . Кроме того, в распоряжении программиста, который решит пользоваться событием scroll , не будет удобного API, позволяющего реализовывать различные сценарии скроллинга. Именно поэтому часто, вместо того, чтобы реализовывать механизмы обработки события scroll самостоятельно, есть смысл применить специализированную библиотеку, авторы которой уже позаботились и о влиянии обработки события scroll на производительность, и об API. Некоторые из этих библиотек даже способны помочь разработчику при возникновении проблем с размерами элементов

Инструменты для создания механизмов скроллинга общего назначения

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

▍ScrollMagic

Библиотека ScrollMagic даёт нам сравнительно простой API, позволяющий создавать различные эффекты при скроллинге. Эта библиотека может работать совместно с различными библиотеками для анимации, наподобие GSAP и Velocity.js. Правда, в последние несколько лет эта библиотека недостаточно хорошо поддерживается. Это привело к тому, что была создана библиотека ScrollScene.

▍ScrollScene

ScrollScene — это, в сущности, обёртка, которая направлена на то, чтобы повысить удобство работы с библиотекой ScrollMagic и (или) с API IntersectionObserver. Здесь используется собственная версия ScrollMagic, которая отличается лучшей поддержкой, чем обычный вариант библиотеки. Тут имеются и дополнительные возможности, наподобие проигрывания видео и поддержки контрольных точек, влияющих на анимацию. Кроме того, эта библиотека использует GSAP.

▍ScrollTrigger

Библиотека ScrollTrigger — это официальный GreenSock-плагин для GSAP. Эта библиотека отличается большим набором возможностей, её API кажется мне самым простым из API существующих библиотек для скроллинга. Используя эту библиотеку, вы полностью контролируете то, где именно начинается и заканчивается анимация скроллинга, вы можете анимировать при прокрутке всё что угодно (WebGL, canvas, SVG, DOM), можете закреплять элементы на время выполнения анимации. Этим возможности данной библиотеки не ограничиваются. Кроме того, эту библиотеку поддерживает GreenSock, получить помощь по её использованию можно на форумах GreenSock.

▍Библиотека, достойная упоминания: Locomotive Scroll

Библиотека Locomotive Scroll не стремится к реализации столь же широкого набора возможностей, как другие библиотеки, о которых мы говорили. Её основная цель — реализация плавной прокрутки. Используя её, кроме того, можно анимировать некоторые свойства DOM-объектов, используя атрибуты data-* , или пользоваться обработчиком onscroll для анимирования объектов других видов.

Сравнение технологий и инструментов

Вот сравнение технологий скроллинга.

API Intersection Observer Плавная прокрутка Точки привязки в CSS CSS-эффект параллакса CSS-свойство position: sticky
Закрепление элементов - - - - +
Эффект параллакса - - - + -
Управление динамикой анимации ± - - ± -
Использование контрольных точек ± - + - -
Динамическая пакетная обработка элементов + - - - -
Поддержка эффектов горизонтального скроллинга + + + + +
Подходит для продакшна (хорошая браузерная поддержка) ± ± ± + ±
Полная свобода в анимировании - - - - -
Поддержка разработчиком n/a n/a n/a n/a n/a
Работа с DOM, Canvas, WebGl, SVG + - - - -
Поддержка изменения размеров элементов + + + + +
Ограничивает анимацию только релевантным разделом + + + - +
Различает направления скроллинга ± - - - -
Технология, встроенная в браузер + + + + +

Вот сравнение рассмотренных библиотек.

ScrollTrigger Locomotive Scroll ScrollScene ScrollMagic
Закрепление элементов + ± + +
Эффект параллакса + + + +
Управление динамикой анимации + ± ± ±
Использование контрольных точек + ± ± ±
Динамическая пакетная обработка элементов + - + -
Поддержка эффектов горизонтального скроллинга + + + +
Подходит для продакшна (хорошая браузерная поддержка) + ± + +
Полная свобода в анимировании + ± + +
Поддержка разработчиком + + + -
Работает с DOM, Canvas, WebGl, SVG + ± + +
Поддержка изменения размеров элементов + + + ±
Ограничивает анимацию только релевантным разделом + - ± ±
Различает направления скроллинга + ± + +
Технология, встроенная в браузер - - - -

Итоги

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

Я обычно, для настройки скроллинга, рекомендую использовать библиотеку ScrollTrigger. Она позволяет достичь всего, на что способен чистый CSS, а так же — многого другого. Эта библиотека берёт на себя заботу о браузерной поддержке тех или иных технологий, облегчает выполнение вычислений, что позволяет тому, кто её использует, просто заниматься своими делами.

Какие технологии вы используете при настройке скроллинга в своих проектах?


Прокрутка — одно из самых древних взаимодействий в вебе. Задолго до появления методов pull-to-refresh и списков бесконечной загрузки скромная полоса прокрутки решила изначальную проблему масштабирования в вебе: как взаимодействовать с контентом, который распространяется за пределы доступной области просмотра?

Сегодня прокрутка всё ещё остаётся самым фундаментальным взаимодействием в Сети, и, возможно, самым неправильно понятым. Например, вы знаете разницу между следующими сценариями?

  • Пользователь прокручивает страницу двумя пальцами на тачпаде
  • Пользователь прокручивает одним пальцем на тачскрине
  • Пользователь прокручивает колесо мыши
  • Пользователь щёлкает по полосе прокрутки и тянет её вниз и вверх
  • Пользователь нажимает стрелки «вверх», «вниз», PageUp, PageDown и «пробел» на клавиатуре

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

Концептуально, веб является однопоточной средой. JavaScript блокирует DOM, а DOM блокирует JavaScript, потому что оба борются за один и тот же поток, часто называемый «основным потоком» или «потоком UI».

Например, если вы добавите этот (ужасный) сниппет JavaScript на страницу, то немедленно заметите ухудшение в работе:


Пока этот JavaScript крутится в бесконечном цикле, кнопки не работают, элементы форм не реагируют и даже анимированные GIF'ки тормозят — во всех смыслах и отношениях страница зависла. Можете изучить эффект в действии в простом демо.

Более того, если вы попытаетесь прокрутить страницу клавишами «вверх» и «вниз» на клавиатуре, страница предсказуемо застрянет, пока JavaScript не прекратит выполнение. Всё это явные свидетельства нашего представления веба как однопоточной среды.

Есть забавная аномалия: если попробовать прокрутку через тачскрин, то страница отлично прокручивается вверх и вниз, хотя JavaScript и блокирует всё остальное на странице. То же самое относится к прокрутке с тачпада, колесом мыши и прокрутке после захвата страницы курсором click-and-drag (в зависимости от браузера).

Каким-то образом некоторые действия по прокрутке могут изменять состояние страницы, в то время как всё остальное — кнопки, поля ввода данных, GIF'ы — полностью зависло. Как мы можем совместить это с нашей теорией однопоточного веба?


Как выясняется, в целом тезис «браузеры однопоточные» правдив, но есть важные исключения. Прокрутка, во всём своём многообразии, является одним из таких исключений.

С годами разработчики браузеров осознали, что выгрузка вспомогательной работы в фоновые потоки может дать значительную выгоду по плавности работы и чувствительности. Прокрутка настолько важна для ключевого опыта работы с браузером, что эту задачу быстро выбрали для такой оптимизации. В наше время все основные браузерные движки (Blink, EdgeHTML, Gecko, WebKit) поддерживают прокрутку за пределами основного потока выполнения в той или иной степени (Firefox последним присоединился к клубу, с версии Firefox 46).

С фоновой прокруткой даже загромождённая страница будет плавно прокручиваться, потому что вся прокрутка выполняется в отдельном потоке. Только если вы попытаетесь взаимодействовать со страницей через некий посторонний механизм, не связанный с прокруткой — нажать клавишу, ввести данные в поле ввода, нажать на ссылку — тогда фасад сбрасывается и суть салонного трюка полностью раскрывает себя. (Учитывая, насколько хорошо он работает, это отличный трюк!)

Правда, у асинхронной прокрутки есть распространённый побочный эффект, который называют эффектом шахматной доски (checkerboarding). Он впервые проявился на в Safari для iOS в виде серых и белых клеток, словно с шахматной доски. В большинстве современных браузеров эффект проявляется как пустое пространство на экране, если вы осуществляете прокрутку быстрее, чем браузер может отрисовать страницу. Это не идеально, но это приемлемый компромисс, по сравнению с заблокированной, дёргающейся или неоткликающейся прокруткой.

К сожалению, не всегда можно легко перенести прокрутку в фоновый поток выполнения. Браузеры могут сделать это только в том случае, если операционная система допускает одновременный ввод, и это может варьироваться от устройства к устройству. В частности, ввод с клавиатуры не настолько оптимизирован, как ввод с мыши или тач-устройств, что в конечном счёте ведёт к более значительным лагам при вводе с клавиатуры во всех браузерах.

Здесь будет поучительной небольшая история. Когда впервые вышли операционные системы вроде Windows и macOS, они допускали только один поток выполнения, и мало кто предвидел необходимость предусмотреть одновременный ввод. Только когда появились многоядерные машины, операционные системы начали встраивать параллелизм в свою архитектуру.

Также как рудиментарные органы животных дают понять их эволюционную историю, однопоточное происхождение операционных систем проявляет себя, если посмотреть на способы прокрутки в вебе. Только если операционная система допускает параллельный ввод — с мыши, клавиатуры или другого устройства — браузеры могут эффективно оптимизировать прокрутку, чтобы на неё не влияло длительное выполнение JavaScript, захламившего основной поток выполнения.

Однако в группе разработки Microsoft Edge мы делаем успехи, чтобы гарантировать плавный и восприимчивый скроллинг, независимо от его метода. В EdgeHTML 14 (который вошёл в состав Windows 10 Anniversary Update) мы поддерживаем фоновую прокрутку для следующих методов:

  • Один палец, тачскрин
  • Два пальца, тачпад
  • Колесо мыши
  • Полоса прокрутки

По результатам тестирования в Windows 10 (14393, Surface Book) и macOS Sierra (10.12, MacBook Air) мы получили следующие результаты:

Два пальца тачпад Тач Колесо мыши Полоса прокрутки Клавиатура
Edge 14 (Windows) Есть Есть Есть Есть Нет
Chrome 56 (Windows) Есть Есть Есть Нет Нет
Firefox 51 (Windows) Нет Нет Нет Нет Нет
Chrome 56 (MacOS) Есть N/A Есть Нет Нет
Firefox 51 (MacOS) Есть N/A Есть Нет Нет
Safari 10.1 (MacOS) Есть N/A Есть Нет Нет

Как демонстрирует* эта таблица, поведение прокрутки может драматически изменяться от браузера к браузеру, и даже от одной ОС к другой. Если вы тестируете один метод прокрутки только в одном браузере, то получите весьма неполные результаты производительности своего сайта, по сравнению с тем, как в реальности с ним работают пользователи!

В целом должно быть ясно, что у прокрутки особенное место в вебе и браузеры очень много работают, чтобы сделать её быстрой и восприимчивой. Однако, есть тонкие способы, как веб-разработчик может непреднамеренно отключить встроенные в браузер оптимизации. Посмотрим на то, как веб-разработчики могут влиять на прокрутку в браузере, по-хорошему и по-плохому.


Фоновая прокрутка даёт ощутимую прибавку в эффективности — прокрутка и JavaScript полностью разделены, позволяя им работать параллельно без помех друг другу.

Но каждый, кто немного разрабатывал веб-страницы, знает, как установить связь между JavaScript и прокруткой:


Когда мы добавляем прослушивающий процесс wheel, который вызывает event.preventDefault() , то он на 100% блокирует прокрутку, как для колеса мыши, так и для тачпада. И очевидно, если прокрутка заблокирована, то фоновая прокрутка тоже заблокирована.

Менее очевидно влияние такого примера:


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

Прослушивание колеса мыши не взаимодействует с нашей большой блокирующей операцией JavaScript, но у них общий цикл событий, так что фоновый поток выполнения должен ждать, пока закончится более длительная операция JavaScript, прежде чем получит ответ от функции прослушивания событий.

Почему он должен ждать? Ну, JavaScript — это динамический язык программирования, и браузер не может знать наверняка, что preventDefault() никогда не вызовут. Даже если для разработчика очевидно, что функция делает просто запись console.log() , разработчики браузеров предпочитают не оставлять шансов. На самом деле, даже пустая function() <> вызовет тот же эффект.

Обратите внимание, что это относится не только к колесу мыши: на тач-устройствах прокрутка тоже может быть заблокирована прослушивающими процессами touchstart или touchmove.

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

Есть несколько интерфейсов JavaScript API, связанных с прокруткой, однако они не блокируют прокрутку. Событие scroll, хотя это в чём-то нелогично, не может блокировать прокрутку, потому что оно запускается после прокрутки, и поэтому является неотменяемым. Также и новый Pointer Events API, представленный в IE и Microsoft Edge, и который недавно начали внедрять в Chrome и Firefox, изначально спроектирован с целью избежать неумышленного блокирования прокрутки.

Даже в тех случаях, когда нам действительно нужно прослушивать события wheel или touchstart, есть определённые хитрости, как веб-разработчики могут гарантировать работу прокрутки с максимальным качеством. Посмотрим на некоторые из этих хитростей.


В предыдущем примере мы видели случай глобального прослушивающего процесса (то есть прикреплённого к window или document). Но что насчёт прослушивающих процессов для индивидуальных элементов прокрутки?

Другими словами, представьте страницу, для которой работает прокрутка, но на странице есть отдельная область с собственной независимой прокруткой. Блокирует ли браузер прокрутку для всей страницы, если вы добавите прослушивающий процесс только в этой области?


Если вы проверите на простой демонстрационной странице, то заметите, что Microsoft Edge и Safari оставят плавную прокрутку для целого документа, если прослушивающий процесс для прокрутки находится в div с независимой прокруткой.

Вот таблица браузеров и их поведения:

Два пальца тачпад Тач Колесо мыши Click-and-drag Клавиатура
Десктопный Edge 14 (Windows) Есть Есть Есть Есть Нет
Десктопный Chrome 56 (Windows) Нет Есть Нет Нет Нет
Десктопный Firefox 51 (Windows) Нет Нет Нет Нет Нет
Десктопный Chrome 56 (MacOS) Нет N/A Нет Нет Нет
Десктопный Firefox 51 (MacOS) Есть N/A Есть Нет Нет
Safari 10.1 (MacOS) Есть N/A Есть Нет Нет

Результаты показывают*, что для веб-разработчиков есть доступные оптимизации, чтобы получить пользу от этих функций браузеров. Вместо использования прослушивающих процессов wheel/touch для всего документа, предпочтительно добавить прослушивающие процессы в конкретный подраздел документа, так что прокрутка останется плавной для всех остальных частей страницы. Другими словами, вместо делегирования прослушивающих процессов wheel/touchstart на максимально высокий уровень, лучше всего изолировать их для элемента, где это нужно.

К сожалению, не все фреймворки JavaScript допускают такую практику — в частности, React, как правило, добавляет глобальный прослушивающий процесс ко всему документу даже если тот должен относиться только к части страницы. Однако есть открытый тикет конкретно для этой проблемы, и парни из React сказали, что с радостью примут пулл-реквест. (Уважение парням из React, которые так быстро среагировали на наше предложение)


Уход от глобальных прослушивающих процессов wheel/touchstart — это хорошая практика, но иногда такое просто невозможно, в зависимости от эффекта, которого вы пытаетесь добиться. И в некоторым роде выглядит глупо, что простое прослушивание событий заставляет браузер остановить весь мир, просто потому что существует гипотетическая вероятность вызова PreventDefault() , и он его ждёт.

К счастью, в браузерах начала появляться новая функция, когда веб-разработчики могут явно пометить прослушивающий процесс как «пассивный» и поэтому избежать ожидания:


С таким подходом браузер будет обрабатывать прокрутку так, как будто прослушивающий процесс wheel вообще отсутствует. Эта функция уже доступна в последних версиях Chrome, Firefox и Safari, и должна скоро появиться в будущем релизе Microsoft Edge. (Обратите внимание, что нужно применять feature detection для поддержки браузеров, которые не распознают пассивные прослушивающие процессы).

Для некоторых событий (в том числе touchstart и touchmove) Chrome с версии 56 принял решение вмешиваться и сделал их пассивными по умолчанию. Имейте в виду эту незначительную разницу между браузерами, когда добавляете прослушивающие процессы!


Как мы видели, прокрутка в вебе — фантастически сложный процесс, и все браузеры находятся на разных этапах улучшения своей производительности. Но в целом мы можем сформулировать некоторые чёткие советы для веб-разработчиков.

Во-первых, лучше не добавлять прослушивающие процессы wheel или touch к глобальным объектам document или window, а вместо этого добавлять их к меньшим элементам с индивидуальной прокруткой. Разработчикам также следует использовать пассивные прослушивающие процессы, где только возможно, с применением feature detection, чтобы избежать проблем совместимости. Использование Pointer Events (там есть polyfill) и прослушивающих событий scroll — тоже верный способ избежать непреднамеренной блокировки прокрутки.

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

Наша группа Microsoft Edge продолжит инновации в данной области, чтобы обеспечить плавную прокрутку для большего количества сайтов и пользователей. Скажем это для скромного скроллбара — самого старого и неоднозначного взаимодействия в вебе!

* Результаты получены на последней версии каждого браузера в феврале 2017 года. С тех пор Firefox 52 обновил поддержку прокрутки, и теперь соответствует поведению Edge 14 во всех тестах, за исключением скроллинга полосой прокрутки. Надеемся, остальные браузеры тоже сделают улучшения в реализации прокрутки и сделают веб быстрее и более восприимчивым!

ancient_scroll_1600_clr

Мы будем называть scroll-эффектами любые сценарии и приемы, реализуемые на веб-странице, так или иначе связанные с направлением и/или позицией прокрутки этой страницы относительно окна браузера.

К сожалению, пока не существует никаких отраслевых стандартов по поводу именования различных видов скролл-эффектов. Поэтому давайте рассмотрим самые популярные из них и дадим им собственные, наиболее подходящие по смыслу названия.

Эффект движения слоев страницы с разной скоростью при скролле. Обычно, в соответствии с оптическим представлением параллакса, слои, находящиеся ближе к наблюдателю, должны двигаться быстрее слоев, находящихся на удалении.

Надо сказать, что СSS свойство position: sticky (позволяет с легкостью реализовывать подобные эффекты без применения javascript) описано в черновике спецификации CSS Positioned Layout Module Level. Но вот с поддержкой браузерами пока совсем туго.

Эффект, по сути, похож на предыдущий, но элемент прячется за границей окна при скролле вниз и появляется только при обратном скролле (вверх). Будет намного легче понять, о чем идет речь, немного поигравшись с демо.

Разновидности сценариев для визуализации текушего положения пользователя на странице при скролле. Например, в этом демо есть веселый индикатор прокрутки внизу страницы.

Этот сценарий подразумевает последовательное применение stcicky-эффекта к заголовкам разделов страницы при скролле. А вот и демо

Этот сценарий хорошо известен под именем scroll spy в twitter bootstrap. Он подразумевает подсветку пунктов меню навигации, в зависимости от положения скролла, например, как в этом демо.

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

Общие проблемы при реализации любых сценариев со скролл-эффектами.

Во-первых, при написании скролл-эффектов нужно учитывать большое количество факторов и величин:

  • Размер всего документа.
  • Размеры и позиции элементов, участвующих в сценарии, а также в некоторых случаях и их контейнеров.
  • Размер и текущее положение видимой части документа (viewport) при скролле.
  • Направление скролла.
  • Адаптация при изменении размеров окна с отзывчивым (responsive) дизайном

Во-вторых, математические вычисления для описания сценариев получаются довольно массивными, а их сложность возрастает с ростом количества эффектов.

В-третьих, на мобильных девайсах все работает плохо и с тормозами. Javascript изначально работает медленнее. В добавок к этому, мобильные браузеры блокируют выполнение javascript во время скролла.

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

Что такое Scroolly?

Правила, их границы и области действия.

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

Чтобы было проще понять о чем идет речь, приведу абстрактный пример:

  1. Нужно плавно показать и плавно скрыть некоторый элемент, когда при скролле он будет входить в область видимости и выходить из нее. Элемент должен начать появляться после того, как его верхняя кромка будет на 100px выше нижней границы видимой области окна и полностью появится, когда его нижняя кромка будет на 100px выше нижней границы видимой области окна. Та же логика с исчезновением, только в симметрично обратном порядке.
  2. Элемент нужно повернуть на 180° во время скролла, пока он будет находится в зоне ±30% от центра видимой зоны.

Чертовски сложно воспринимается на слух, не правда ли? Лучше посмотрим на демо.

В итоге, здесь мы можем выделить 3 области действия правил c 6-ю границами. Давайте опишем их:

  1. Точка, находящаяся на 100px ниже верхней границы элемента, совпадает с нижней границей viewport (элемент начинает появляться)
  2. Точка, находящаяся на 100px выше верхней границы элемента, совпадает с нижней границей viewport (элемент заканчивает появляться)
  3. Точка, находящаяся на 30% ниже центра viewport, совпадает с центром элемента (элемент начинает поворот)
  4. Точка, находящаяся на 30% выше центра viewport, совпадает с центром элемента (элемент заканчивает поворот)
  5. Точка, находящаяся на 100px ниже верхней границы элемента, совпадает с верхней границей viewport (элемент начинает исчезать)
  6. Точка, находящаяся на 100px выше верхней границы элемента, совпадает с верхней границей viewport (элемент заканчивает исчезать)

Scroolly спешит на помощь.

Вся прелесть scroolly заключается в том, что каждая из этих границ областей действия правил задается с помощью вот такого наглядного синтаксиса:

  1. el-top = vp-bottom - 100px (элемент начинает появляться)
  2. el-bottom = vp-bottom - 100px (элемент заканчивает появляться)
  3. el-center = vp-center + 30vp (элемент начинает поворот)
  4. el-center = vp-center - 30vp (элемент заканчивает поворот)
  5. el-top = vp-top + 100px (элемент начинает исчезать)
  6. el-bottom = vp-top + 100px (элемент заканчивает исчезать)

А весь сценарий описывается так:

leading-actors (2)

У каждого из них есть опорные точки, которые можно использовать в синтаксисе scroolly:

viewport: vp-top , vp-center , vp-bottom
элемент: el-top , el-center , el-bottom
контейнер: con-top , con-center , con-bottom
документ: doc-top , doc-center , doc-bottom

anchors (2)

Вот несколько примеров описания областей действия правил c помощью синтаксиса scrolly:

viewport-document

viewport-element (5)

Документация

Если Вас заитересовал плагин scroolly обязательно посмотрите официальную документацию. А она существует, и даже представлена в 2-х вариантах:

Ну и самое главное: обязательно посмотрите видео с нашей конференции 4front, на котором Борис сам захватывающе рассказал про скролл-эффекты в целом и scroolly в частности.

В заключение

Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

Как найти ширину окна браузера? Как узнать всю высоту страницы, с учётом прокрутки? Как прокрутить её из JavaScript?

С точки зрения HTML, документ – это document.documentElement . У этого элемента, соответствующего тегу <html> , есть все стандартные свойства и метрики и, в теории, они и должны нам помочь. Однако, на практике есть ряд нюансов, именно их мы рассмотрим в этой главе.

Ширина/высота видимой части окна

Свойства clientWidth/Height для элемента document.documentElement – это как раз ширина/высота видимой области окна.


Например, кнопка ниже выведет размер такой области для этой страницы:

В чём отличие? Оно небольшое, но чрезвычайно важное.

Свойства clientWidth/Height , если есть полоса прокрутки, возвращают именно ширину/высоту внутри неё, доступную для документа, а window.innerWidth/Height – игнорируют её наличие.

Если справа часть страницы занимает полоса прокрутки, то эти строки выведут разное:

Обычно нам нужна именно доступная ширина окна, например, чтобы нарисовать что-либо, то есть за вычетом полосы прокрутки. Поэтому используем documentElement.clientWidth .

Ширина/высота страницы с учётом прокрутки

Теоретически, видимая часть страницы – это documentElement.clientWidth/Height , а полный размер с учётом прокрутки – по аналогии, documentElement.scrollWidth/scrollHeight .

Это верно для обычных элементов.

А вот для страницы с этими свойствами возникает проблема, когда прокрутка то есть, то нет. В этом случае они работают некорректно. В браузерах Chrome/Safari и Opera при отсутствии прокрутки значение documentElement.scrollHeight в этом случае может быть даже меньше, чем documentElement.clientHeight , что, конечно же, выглядит как совершеннейшая чепуха и нонсенс.

Эта проблема возникает именно для documentElement , то есть для всей страницы.

Надёжно определить размер страницы с учётом прокрутки можно, взяв максимум из нескольких свойств:

Почему так? Лучше и не спрашивайте, это одно из редких мест, где просто ошибки в браузерах. Глубокой логики здесь нет.

Получение текущей прокрутки

У обычного элемента текущую прокрутку можно получить в scrollLeft/scrollTop .

Что же со страницей?

Большинство браузеров корректно обработает запрос к documentElement.scrollLeft/Top , однако Safari/Chrome/Opera есть ошибки (к примеру 157855, 106133), из-за которых следует использовать document.body .

Чтобы вообще обойти проблему, можно использовать специальные свойства window.pageXOffset/pageYOffset :

Кросс-браузерный вариант с учётом IE8 предусматривает откат на documentElement :

Изменение прокрутки: scrollTo, scrollBy, scrollIntoView

Чтобы прокрутить страницу при помощи JavaScript, её DOM должен быть полностью загружен.

На обычных элементах свойства scrollTop/scrollLeft можно изменять, и при этом элемент будет прокручиваться.

Никто не мешает точно так же поступать и со страницей. Во всех браузерах, кроме Chrome/Safari/Opera можно осуществить прокрутку установкой document.documentElement.scrollTop , а в указанных – использовать для этого document.body.scrollTop . И будет работать. Можно попробовать прокручивать и так и эдак и проверять, подействовала ли прокрутка, будет кросс-браузерно.

Но есть и другое, простое и универсальное решение – специальные методы прокрутки страницы window.scrollBy(x,y) и window.scrollTo(pageX,pageY).

Метод scrollBy(x,y) прокручивает страницу относительно текущих координат.

Например, кнопка ниже прокрутит страницу на 10px вниз:

Метод scrollTo(pageX,pageY) прокручивает страницу к указанным координатам относительно документа.

Он эквивалентен установке свойств scrollLeft/scrollTop .

Чтобы прокрутить в начало документа, достаточно указать координаты (0,0) .

scrollIntoView

Для полноты картины рассмотрим также метод elem.scrollIntoView(top).

Метод elem.scrollIntoView(top) вызывается на элементе и прокручивает страницу так, чтобы элемент оказался вверху, если параметр top равен true , и внизу, если top равен false . Причём, если параметр top не указан, то он считается равным true .

Кнопка ниже прокрутит страницу так, чтобы кнопка оказалась вверху:

А следующая кнопка прокрутит страницу так, чтобы кнопка оказалась внизу:

Запрет прокрутки

Иногда бывает нужно временно сделать документ «непрокручиваемым». Например, при показе большого диалогового окна над документом – чтобы посетитель мог прокручивать это окно, но не документ.

Чтобы запретить прокрутку страницы, достаточно поставить document.body.style.overflow = "hidden" .

При этом страница замрёт в текущем положении.

При нажатии на верхнюю кнопку страница замрёт на текущем положении прокрутки. После нажатия на нижнюю – прокрутка возобновится.

Вместо document.body может быть любой элемент, прокрутку которого необходимо запретить.

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

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

Итого

Для получения размеров видимой части окна: document.documentElement.clientWidth/Height

Для получения размеров страницы с учётом прокрутки:

Прокрутка окна:

На всякий случай – вот самый кросс-браузерный способ, учитывающий IE7- в том числе:

Установить прокрутку можно при помощи специальных методов:

  • window.scrollTo(pageX,pageY) – абсолютные координаты,
  • window.scrollBy(x,y) – прокрутить относительно текущего места.
  • elem.scrollIntoView(top) – прокрутить, чтобы элемент elem стал виден.

Задачи

Полифилл для pageYOffset в IE8

Обычно в IE8 не поддерживается свойство pageYOffset . Напишите полифилл для него.

Читайте также: