Создание компонента историй

Базовый обзор того, как создать в Интернете опыт, аналогичный Instagram Stories.

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

Демо

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

Если вы предпочитаете видео, вот версия этого поста на YouTube:

Обзор

Два популярных примера пользовательского опыта в Stories — это истории Snapchat и истории Instagram (не говоря уже о целой флотилии). В общем смысле, Stories — это, как правило, мобильный шаблон навигации по нескольким подпискам, ориентированный на касания. Например, в Instagram пользователи открывают историю друга и просматривают фотографии в ней. Обычно они просматривают столько друзей одновременно. Нажимая на правую сторону устройства, пользователь переходит к следующей истории этого друга. Свайп вправо позволяет перейти к другому другу. Компонент Story довольно похож на карусель, но позволяет перемещаться по многомерному массиву, а не по одномерному. Это как если бы внутри каждой карусели была карусель. 🤯

Визуализированный многомерный массив с использованием карточек. Слева направо — стопка карточек с фиолетовыми рамками, внутри каждой карточки — 1-множество карточек с голубыми рамками. Список в списке.
1-я карусель друзей
2-я «сложенная» карусель историй
👍 Список в списке, он же: многомерный массив

Выбор правильных инструментов для работы

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

CSS-сетка

Наш макет оказался несложной задачей для CSS Grid, поскольку он оснащен несколькими мощными способами обработки контента.

Макет «Друзья»

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

.stories {
  inline-size: 100vw;
  block-size: 100vh;

  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;

  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}

/* desktop constraint */
@media (hover: hover) and (min-width: 480px) {
  max-inline-size: 480px;
  max-block-size: 848px;
}
Использование режима устройства Chrome DevTools для выделения столбцов, созданных Grid

Давайте разберем эту grid :

  • Мы явно заполняем область просмотра на мобильном устройстве значениями 100vh и 100vw и ограничиваем размер на десктопе.
  • / разделяет наши шаблоны строк и столбцов
  • auto-flow преобразуется в grid-auto-flow: column
  • Шаблон автозаполнения составляет 100% , что в данном случае равно ширине окна прокрутки.

На мобильном телефоне это можно представить так: размер строки равен высоте области просмотра, а размер каждого столбца — ширине. Продолжая пример с историями Snapchat и Instagram, каждый столбец будет историей друга. Мы хотим, чтобы истории друзей выходили за пределы области просмотра, чтобы было куда прокручивать. Grid создаст столько столбцов, сколько необходимо для разметки HTML для каждой истории друга, создавая динамичный и адаптивный контейнер с прокруткой. Grid позволил нам централизовать весь эффект.

Укладка

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

С помощью CSS-сетки мы можем определить сетку из одной ячейки (т. е. квадрат), в которой строки и столбцы имеют общий псевдоним ( [story] ), а затем каждому дочернему элементу назначается это псевдонимное пространство из одной ячейки:

.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
.story {
  grid-area: story;
  background-size: cover;
  
}

Это позволяет нашему HTML-коду контролировать порядок наложения элементов и сохранять их в потоке. Обратите внимание, что нам не нужно было ничего делать с absolute позиционированием или z-index , а также корректировать бокс с помощью height: 100% или width: 100% . Родительская сетка уже определила размер области просмотра изображения истории, поэтому ни одному из этих компонентов истории не нужно было указывать, как её заполнить!

Точки привязки прокрутки CSS

Спецификация CSS Scroll Snap Points позволяет легко фиксировать элементы в области просмотра при прокрутке. До появления этих свойств CSS приходилось использовать JavaScript, и это было… мягко говоря, сложно. Ознакомьтесь со статьёй Сары Драснер «Введение в CSS Scroll Snap Points», где подробно объясняется, как их использовать.

Горизонтальная прокрутка без стилей scroll-snap-points и с ними. Без неё пользователи могут свободно прокручивать страницу как обычно. С ней браузер плавно обхватывает каждый элемент.
родитель
.stories {
  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}
Родительский элемент с прокруткой сверху определяет поведение привязки.
ребенок
.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
Дети сами выбирают быть легкой мишенью.

Я выбрал Scroll Snap Points по нескольким причинам:

  • Свободный доступ . В спецификации Scroll Snap Points указано, что нажатие клавиш «Стрелка влево» и «Стрелка вправо» должно по умолчанию перемещать курсор через точки привязки.
  • Развивающаяся спецификация . Спецификация Scroll Snap Points постоянно обрастает новыми функциями и улучшениями, а это значит, что мой компонент Stories, вероятно, с этого момента будет становиться только лучше.
  • Простота реализации . Точки прокрутки предназначены для горизонтальной навигацией по страницам с сенсорным управлением.
  • Свободная инерция в стиле платформы . Каждая платформа будет прокручиваться и останавливаться в своём стиле, в отличие от нормализованной инерции, которая может иметь странный стиль прокрутки и отдыха.

Совместимость со всеми браузерами

Мы протестировали его в Opera, Firefox, Safari и Chrome, а также на Android и iOS. Вот краткий список веб-функций, в возможностях и поддержке которых мы обнаружили различия.

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

scroll-snap-stop

Карусели были одним из основных вариантов использования в UX, что побудило создать спецификацию CSS Scroll Snap Points. В отличие от историй, карусель не всегда должна останавливаться на каждом изображении после взаимодействия с ним пользователя. Быстрый переход по карусели может быть приемлемым или даже желательным. С другой стороны, истории лучше всего просматривать по одной, и именно это обеспечивает scroll-snap-stop .

.user {
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

На момент написания этой статьи scroll-snap-stop поддерживался только в браузерах на базе Chromium. Проверьте совместимость браузеров на наличие обновлений. Однако это не блокировщик. Это просто означает, что в неподдерживаемых браузерах пользователи могут случайно пропустить друга. Поэтому пользователям придётся быть внимательнее, иначе придётся написать JavaScript, чтобы пропущенный друг не отмечался как просмотренный.

Если вам интересно, более подробную информацию можно найти в спецификации .

overscroll-behavior

Вы когда-нибудь прокручивали модальное окно и вдруг начинали прокручивать содержимое за ним? overscroll-behavior позволяет разработчику зафиксировать прокрутку и не дать ей уйти. Это удобно в самых разных случаях. Компонент «Мои истории» использует это свойство, чтобы предотвратить выход за пределы компонента при дополнительных смахиваниях и жестах прокрутки.

.stories {
  overflow-x: auto;
  overscroll-behavior: contain;
}

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

scrollIntoView({behavior: 'smooth'})

Когда пользователь нажимает или щёлкает по истории друга и достигает её конца, нужно перейти к следующему другу в заданной точке привязки прокрутки. С помощью JavaScript мы смогли обратиться к следующему другу и запросить прокрутку его истории в область видимости. Базовая поддержка этой функции отличная; каждый браузер прокручивал историю в область видимости. Но не все браузеры делали это 'smooth' . Это означает, что история прокручивается в область видимости, а не прикрепляется.

element.scrollIntoView({
  behavior: 'smooth'
})

Safari был единственным браузером, не поддерживающим behavior: 'smooth' в данном случае. Проверьте совместимость браузеров с обновлениями.

Практический

Теперь, когда вы знаете, как это сделал я, как бы поступили вы?! Давайте разнообразим наши подходы и изучим все способы создания контента в интернете. Создайте Glitch , отправьте мне в Твиттер свою версию, и я добавлю её в раздел «Ремиксы сообщества» ниже.

Ремиксы сообщества