Хорошо контролируемая прокрутка с помощью CSS Scroll Snap.

Создавайте хорошо контролируемые процессы прокрутки, объявляя позиции привязки прокрутки.

Роберт Флэк
Robert Flack
Маджид Валипур
Majid Valipour

Функция CSS Scroll Snap позволяет веб-разработчикам создавать хорошо контролируемые возможности прокрутки, объявляя позиции привязки прокрутки. Статьи с разбивкой на страницы и карусели изображений — два часто используемых примера. CSS Scroll Snap предоставляет простой в использовании и последовательный API для создания этих популярных шаблонов UX.

Фон

Случай с привязкой к прокрутке

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

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

Веб-разработчики долгое время полагались на решения на основе JavaScript для управления прокруткой, чтобы устранить этот недостаток. Однако решения на основе JavaScript не могут обеспечить решение полной точности из-за отсутствия примитивов настройки прокрутки или доступа к составной прокрутке. CSS Scroll Snap обеспечивает быстрое, высокоточное и простое в использовании решение, которое работает одинаково во всех браузерах.

CSS Scroll Snap позволяет веб-авторам отмечать каждый контейнер прокрутки границами для операций прокрутки, на которых они должны закончиться. Затем браузеры выбирают наиболее подходящую конечную позицию в зависимости от особенностей операции прокрутки, макета и видимости контейнера прокрутки, а также деталей позиций привязки, а затем плавно переходят к ней. Возвращаясь к нашему предыдущему примеру, когда пользователь заканчивает прокручивать карусель, ее видимое изображение фиксируется на месте. Никаких корректировок прокрутки не требуется с помощью JavaScript.

Пример использования css scroll snap с каруселью изображений.
Пример использования css scroll snap с каруселью изображений. Здесь scroll snap обеспечивает в конце прокрутки выравнивание горизонтального центра изображения с горизонтальным центром контейнера прокрутки.

CSS-прокрутка Snap

Привязка прокрутки — это процесс регулировки смещения прокрутки контейнера прокрутки для достижения предпочтительного положения привязки после завершения операции прокрутки.

Контейнер прокрутки можно включить в режим привязки прокрутки с помощью свойства scroll-snap-type . Это сообщает браузеру, что следует рассмотреть возможность привязки этого контейнера прокрутки к позициям привязки, создаваемым его потомками. scroll-snap-type определяет ось прокрутки: x , y или both , а также строгость привязки: mandatory или proximity . Подробнее об этом позже.

Позицию привязки можно задать, указав желаемое выравнивание для элемента. Эта позиция представляет собой смещение прокрутки, на котором ближайший родительский контейнер прокрутки и элемент выравниваются в соответствии с заданной осью. Возможны следующие варианты выравнивания по каждой оси: start , end , center .

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

Пример различных выравниваний по горизонтальной оси прокрутки.

Следующие примеры иллюстрируют, как использовать эти концепции.

Привязка к прокрутке часто используется в карусели изображений. Например, чтобы создать горизонтальную карусель изображений, которая привязывается к каждому изображению при прокрутке, можно указать для контейнера прокрутки обязательный scroll-snap-type по горизонтальной оси. Для каждого изображения установите свойство scroll-snap-align: center чтобы привязка центрировала изображение в карусели.

#gallery {
  scroll-snap-type: x mandatory;
  overflow-x: scroll;
  display: flex;
}

#gallery img {
   scroll-snap-align: center;
}
<div id="gallery">
  <img src="cat.jpg">
  <img src="dog.jpg">
  <img src="another_cute_animal.jpg">
</div>

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

Пример: страница с пройденным маршрутом

Другой распространенный случай, когда привязка к прокрутке может быть полезна, — это страницы с несколькими логическими разделами для вертикальной прокрутки, например, типичная страница товара. scroll-snap-type: y proximity; более естественно подходит для таких случаев. Этот подход не мешает пользователю прокручивать страницу до середины определенного раздела, но также привязывается и привлекает внимание к новому разделу, когда он прокручивает страницу достаточно близко.

Вот как этого можно добиться:

article {
  scroll-snap-type: y proximity;
  /* Reserve space for header plus some extra space for sneak peeking. */
  scroll-padding-top: 15vh;
  overflow-y: scroll;
}
section {
  /* Snap align start. */
  scroll-snap-align: start;
}
header {
  position: fixed;
  height: 10vh;
}
<article>
  <header> Header </header>
  <section> Section One </section>
  <section> Section Two </section>
  <section> Section Three </section>
</article>

Отступы и поля прокрутки

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

Свойство scroll-padding — это новое CSS-свойство, которое можно использовать для настройки эффективной видимой области контейнера прокрутки (snapport), используемой при расчёте выравнивания привязки прокрутки. Это свойство определяет отступ относительно поля padding контейнера прокрутки. В нашем примере был добавлен дополнительный отступ 15vh в верхнюю часть, что указывает браузеру использовать более низкое положение, на 15vh ниже верхнего края контейнера прокрутки, в качестве его вертикального начального края для привязки прокрутки. При привязке начальный край целевого элемента привязки будет выровнен с этим новым положением, оставляя свободное пространство сверху.

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

Вы могли заметить, что в этих двух свойствах отсутствует слово « snap ». Это сделано намеренно, поскольку они фактически изменяют поле для всех соответствующих операций прокрутки, а не просто привязывают прокрутку. Например, Chrome учитывает их при расчёте размера страницы для операций постраничной прокрутки, таких как PageDown и PageUp, а также при расчёте величины прокрутки для операции Element.scrollIntoView() .

Взаимодействие с другими API прокрутки

API прокрутки DOM

Привязка прокрутки происходит после всех операций прокрутки, включая инициированные скриптом. При использовании API, таких как Element.scrollTo , браузер вычисляет предполагаемое положение прокрутки для операции, а затем применяет соответствующую логику привязки для определения конечного положения привязки. Таким образом, пользовательскому скрипту не требуется выполнять какие-либо ручные вычисления для привязки.

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

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

Поведение прокрутки

API поведения прокрутки управляет тем, как прокрутка привязывается к нескольким элементам, и на него не влияет привязка прокрутки.

Предостережения и передовой опыт

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

Во многих случаях привязку прокрутки можно добавить как улучшение без необходимости определения функций. При необходимости используйте @supports или CSS.supports для определения поддержки CSS Scroll Snap. Избегайте использования scroll-snap-type , который также присутствует в устаревшей спецификации.

Распознавание функций в CSS

@supports (scroll-snap-align: start) {
  article {
    scroll-snap-type: y proximity;
    scroll-padding-top: 15vh;
    overflow-y: scroll;
  }
}

Обнаружение функций в JavaScript

if (CSS.supports('scroll-snap-align: start')) {
  // use css scroll snap
} else {
  // use fallback
}

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

Будущая работа

В недавнем опросе, проведённом командой Chrome , особое внимание уделялось удобству прокрутки. Результаты опроса выявили несколько областей, требующих дополнительной работы для сокращения разрыва между библиотеками плагинов и CSS. В дальнейшем работа будет сосредоточена на scroll-snap , включая:

  1. Доступность API и совместимость со всеми браузерами.
  2. Работа над новыми CSS API, такими как scroll-start .
  3. Работайте над новыми событиями JS, такими как snapChanged() .