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

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

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

Демо

Если вы предпочитаете видео, вот версия этого поста на 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> , чтобы сообщить браузеру, что вашей странице нужны как светлые, так и тёмные стили, предоставляемые user-agent. Это может быть как тёмный, так и светлый режим, в зависимости от того, как вы на это смотрите:

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

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

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

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

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

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

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

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

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

Показаны 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;
  }
}

Фокус

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

.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 и телевизионных приставках. Поскольку сетка скроллера медиа-контента задаёт только направление и интервал, размер может изменяться внутри медиазапроса, который проверяет поддержку соотношения сторон. Постепенное развитие более динамичных скроллеров медиа-контента.

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

@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_HERE

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

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

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

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

ALT_TEXT_HERE

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

ALT_TEXT_HERE

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

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

Заключение

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

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

Источник

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

Пока что здесь нечего смотреть!