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

Базовый обзор того, как создать адаптивную горизонтальную прокрутку для телевизоров, телефонов, настольных компьютеров и т. д.

В этом посте я хочу поделиться мыслями о том, как создать горизонтальную прокрутку в Интернете, которая будет минимальной, отзывчивой, доступной и будет работать в браузерах и платформах (например, на телевизорах!). Попробуйте демо .

Демо

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

Обзор

Мы создадим макет с горизонтальной прокруткой, предназначенный для размещения миниатюр мультимедиа или продуктов. Компонент начинается как скромный список <ul> , но с помощью CSS преобразуется в удобный и плавный интерфейс прокрутки, демонстрирующий изображения и привязывающий их к сетке. JavaScript добавлен для облегчения взаимодействия с перемещаемым индексом, помогая пользователям клавиатуры не перемещаться по более чем 100 элементам. Кроме того, используется экспериментальный медиа-запрос prefers-reduced-data для превращения медиа-прокрутки в облегченную прокрутку заголовков.

Начните с доступной разметки

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

Доставьте список с помощью элемента <ul> :

<ul class="horizontal-media-scroller">
  <li></li>
  <li></li>
  <li></li>
  ...
<ul>

Сделайте элементы списка интерактивными с помощью элемента <a> :

<li>
  <a href="#">
    ...
  </a>
</li>

Используйте элемент <figure> для семантического представления изображения и его подписи:

<figure>
  <picture>
    <img alt="..." loading="lazy" src="https://picsum.photos/500/500?1">
  </picture>
  <figcaption>Legends</figcaption>
</figure>

Обратите внимание на атрибуты alt и loading в <img> . Альтернативный текст для скроллера мультимедиа — это возможность UX , которая помогает добавить к миниатюре дополнительный контекст или в качестве резервного текста, если изображение не загрузилось, или предоставляет голосовой пользовательский интерфейс для пользователей, использующих вспомогательные технологии, такие как программа чтения с экрана. Узнайте больше из статьи «Пять золотых правил обеспечения соответствия замещающему тексту» .

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

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

Используйте color-scheme в качестве тега <meta> , чтобы сигнализировать браузеру, что вашей странице нужны как светлые, так и темные стили пользовательского агента. Это бесплатный темный режим или светлый режим, в зависимости от того, как вы на него смотрите:

<meta name="color-scheme" content="dark light">

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

Узнайте больше от Томаса Штайнера на https://web.dev/color-scheme/ .

Добавить контент

Учитывая приведенную выше структуру контента ul > li > a > figure > picture > img , следующая задача — добавить изображения и заголовки для прокрутки. Я упаковал демо-версию статическими изображениями-заполнителями и текстом, но вы можете использовать для этого свой любимый источник данных.

Добавьте стиль с помощью CSS

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

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

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

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

Контейнер позволяет переопределить размер столбца, указав размер по умолчанию в качестве настраиваемого свойства. Этот макет сетки ориентирован на размер столбцов, он управляет только интервалом и направлением:

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2); /* parent owned value for children to be relative to*/
  margin: 0;
}

Пользовательское свойство затем используется элементом <picture> для создания нашего базового соотношения сторон: поля:

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  & picture {
    inline-size: var(--size);
    block-size: var(--size);
  }
}

Используя еще несколько второстепенных стилей, завершите основу медиа-скроллера:

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  & > li {
    display: inline-block; /* removes the list-item bullet */
  }

  & picture {
    inline-size: var(--size);
    block-size: var(--size);
  }
}

Установка overflow устанавливает <ul> , чтобы разрешить прокрутку и навигацию с помощью клавиатуры по его списку, затем у каждого прямого дочернего элемента <li> удаляется ::marker , получая новый тип отображения inline-block .

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

img {
  /* smash into whatever box it's in */
  inline-size: 100%;
  block-size: 100%;

  /* don't squish but do cover the space */
  object-fit: cover;

  /* soften the edges */
  border-radius: 1ex;
  overflow: hidden;

  /* if empty, show a gradient placeholder */
  background-image:
    linear-gradient(
      to bottom,
      hsl(0 0% 40%),
      hsl(0 0% 20%)
    );
}

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

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

Чтобы создать макет прокрутки от края до края, который соответствует нашей типографике и линиям макета, используйте padding , соответствующий scroll-padding :

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  padding-inline: var(--gap);
  scroll-padding-inline: var(--gap);
  padding-block: calc(var(--gap) / 2); /* make space for scrollbar and focus outline */
}

Исправление ошибки заполнения горизонтальной прокрутки. Выше показано, насколько легко должно быть заполнение контейнера прокрутки, но с ним возникают серьезные проблемы совместимости (хотя исправлено в Chromium 91+!). Здесь можно немного истории, но вкратце это то, что отступы не всегда учитывались при прокрутке.

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

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

.horizontal-media-scroller > li:last-of-type figure {
  position: relative;

  &::after {
    content: "";
    position: absolute;

    inline-size: var(--gap);
    block-size: 100%;

    inset-block-start: 0;
    inset-inline-end: calc(var(--gap) * -1);
  }
}

Использование логических свойств позволяет медиа-прокрутке работать в любом режиме письма и направлении документа.

Привязка прокрутки

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

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  padding-inline: var(--gap);
  scroll-padding-inline: var(--gap);
  padding-block-end: calc(var(--gap) / 2);

  scroll-snap-type: inline mandatory;

  & figure {
    scroll-snap-align: start;
  }
}

Фокус

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

.horizontal-media-scroller a {
  outline-offset: 12px;

  &:focus {
    outline-offset: 7px;
  }

  @media (prefers-reduced-motion: no-preference) {
    & {
      transition: outline-offset .25s ease;
    }
  }
}

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

Индекс перемещения

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

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

Чтобы создать такой опыт, JavaScript должен отслеживать события клавиатуры и события фокуса. Я создал небольшую библиотеку с открытым исходным кодом на npm , чтобы упростить взаимодействие с пользователем. Вот как его использовать для трех скроллеров:

import {rovingIndex} from 'roving-ux';

rovingIndex({
  element: someElement
});

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

document.querySelectorAll('.horizontal-media-scroller')
  .forEach(scroller =>
    rovingIndex({
      element: scroller,
      target: 'a',
}))

Чтобы узнать больше об этом эффекте, посмотрите библиотеку с открытым исходным кодом roving-ux .

Соотношение сторон

На момент написания этой статьи поддержка aspect-ratio в Firefox была отмечена флагом, но доступна в браузерах Chromium или телеприставках. Поскольку макет сетки медиа-прокрутки определяет только направление и интервал, размер может измениться внутри медиа-запроса, функция которого проверяет поддержку соотношения сторон. Прогрессивное улучшение в виде более динамичных медиа-скроллеров.

Рамка с соотношением сторон 4:4 показана рядом с другими используемыми соотношениями сторон: 16:9 и 4:3.

@supports (aspect-ratio: 1) {
  .horizontal-media-scroller figure > picture {
    inline-size: auto; /* for a block-size driven ratio */
    aspect-ratio: 1; /* boxes by default */

    @nest section:nth-child(2) & {
      aspect-ratio: 16/9;
    }

    @nest section:nth-child(3) & {
      /* double the size of the others */
      block-size: calc(var(--size) * 2);
      aspect-ratio: 4/3;

      /* adjust size to fit more items into the viewport */
      @media (width <= 480px) {
        block-size: calc(var(--size) * 1.5);
      }
    }
  }
}

Если браузер поддерживает синтаксис aspect-ratio , изображения медиа-прокрутки обновляются до размера с aspect-ratio . Используя черновой синтаксис вложения, каждое изображение меняет соотношение сторон в зависимости от того, находится ли оно в первой, второй или третьей строке. Синтаксис гнезда также позволяет задавать некоторые небольшие настройки области просмотра прямо вместе с другой логикой изменения размеров.

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

Предпочитает сокращенные данные

Хотя следующий метод доступен только с помощью флага в Canary , я хотел бы рассказать, как я могу сэкономить значительное время загрузки страницы и использование данных с помощью нескольких строк CSS. Медиа prefers-reduced-data уровня 5 позволяет узнать, находится ли устройство в каких-либо состояниях с уменьшенным объемом данных, например в режиме экономии данных. Если да, я могу изменить документ и в данном случае скрыть изображения.

ALT_TEXT_ЗДЕСЬ

figure {
  @media (prefers-reduced-data: reduce) {
    & {
      min-inline-size: var(--size);

      & > picture {
        display: none;
      }
    }
  }
}

Контент по-прежнему доступен для навигации, но без затрат на загрузку тяжелых изображений. Вот сайт перед добавлением CSS prefers-reduced-data :

(7 запросов, 100 КБ ресурсов за 131 мс)

ALT_TEXT_ЗДЕСЬ

Вот производительность сайта после добавления CSS prefers-reduced-data :

ALT_TEXT_ЗДЕСЬ

(71 запрос, 1,2 Мб ресурсов за 1,07 с)

На 64 запроса меньше, то есть ~60 изображений в области просмотра (тесты, проведенные на широком экране) этой вкладки браузера, увеличение загрузки страницы примерно на 80 % и 10 % данных по проводной сети. Довольно мощный CSS.

Заключение

Теперь, когда вы знаете, как я это сделал, как бы вы поступили?! 🙂

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

Источник

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

Здесь пока нечего смотреть!