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

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

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

Демо

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

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

Обзор

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

Визуализация многомерного массива с помощью карточек. Слева направо находится стопка карточек с фиолетовыми рамками, а внутри каждой карты находится по одной карточке с голубой рамкой. Список в списке.
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 и со стилями. Без него пользователи смогут свободно прокручивать страницы как обычно. Благодаря ему браузер мягко опирается на каждый элемент.
родитель
.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 постоянно получает новые функции и улучшения, а это означает, что мой компонент «Истории», вероятно, с этого момента будет только улучшаться.
  • Простота реализации . Точки привязки прокрутки практически созданы для сенсорного варианта использования горизонтальной пагинации.
  • Инерция в стиле свободной платформы . Каждая платформа будет прокручиваться и отдыхать в своем стиле, в отличие от нормализованной инерции, которая может иметь странный стиль прокрутки и отдыха.

Кроссбраузерная совместимость

Мы тестировали на 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 были двумя браузерами, которые не поддерживали эту функцию, и это совершенно нормально. Эти пользователи получат привычный опыт прокрутки и могут никогда не заметить этого улучшения. Лично я большой поклонник и люблю включать его почти в каждую реализуемую мной функцию прокрутки. Это безобидное дополнение, которое может привести только к улучшению UX.

scrollIntoView({behavior: 'smooth'})

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

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

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

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

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

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