Профессионалы в области UI/UX утверждают, что важно сохранять заинтересованность пользователей, пока они ожидают загрузки контента на страницу.
Традиционно для этого в вебе использовались спиннеры и лоадеры. Это хороший подход, ведь анимированная иконка четко говорит пользователю: про вас не забыли, процесс идет. Однако в современных условиях он уже несколько устарел. Человек понимает, что происходит, но смотреть на движущиеся точки довольно скучно. Каждый оборот спиннера добавляет раздражения.
На смену лоадерам пришли "каркасные" экраны (skeleton screens), которые не просто "тянут время", но и лучше обозначают прогресс загрузки, уменьшая негативные ощущения юзера (loading-time frustration). Другими словами, создают иллюзию того, что контент вот-вот появится.
Сегодня мы будем разбираться, как их делать в React-приложениях.
Глобального погружения в основы CSS, JS или React не будет, поэтому вы можете смело читать дальше, даже если не являетесь экспертом в этих технологиях.
Что такое каркасные экраны?
Каркасный, или скелетный, экран – разновидность интерфейса, которая не содержит реального контента. Такой UI повторяет "настоящую" разметку страницы, но вместо контентных единиц – текста, изображений, карточек, блоков – показывает "заглушки", схожие с ними по форме (обычно серые линии и прямоугольники, а также их группы). Когда контент загружается и занимает свое место в макете, заглушки исчезают. Этот переход выглядит не таким резким, как переход между чистой страницей и заполненной текстом.
Другими словами, это занятый плейсхолдерами вместо реальных данных "скелет" страницы.
Так как скелетный UI напоминает настоящий, пользователь видит структуру страницы даже без контента, и у него создается впечатление, будто загрузка идет быстрее – по крайней мере, что первый этап загрузки уже прошел.
Каркасные экраны отлично сочетаются с техникой ленивой загрузки: постепенное появление элементов выглядит более естественным, когда уже ожидает их.
Другие названия техники:
- призрачные элементы (ghost elements),
- заполнители контента (content placeholders),
- загрузчики контента (content loaders).
Этим подходом пользуются многие сайты, в том числе порталы крупных технологических компаний: Blockchain.com, YouTube, Facebook, Medium.
Типы каркасных экранов
Каркасные экраны бывают разными. Самые популярные – это текстовые и графические (цветные) заполнители.
Текстовые используются чаще всего, так как они максимально просты в реализации. Разработчику не нужно знать особенности реального контента, чтобы заменить его заполнителем.
Графические каркасы сложнее – они зависят от контента, который замещают, и встречаются реже.
Готовые решения
Для быстрой реализации паттерна каркасных экранов в вашем приложении можно воспользоваться готовыми решениями. Для React они, конечно, тоже есть. Рассмотрим парочку для примера.
React Placeholder
Репозиторий: buildo/react-placeholder
Загрузка пакета:
Достоинства
- Поддерживается пульсирующая анимация (создает эффект движения на элементах-плейсхолдерах).
- API на основе компонентов.
Недостатки
- Каркасные компоненты поддерживаются по отдельности, поэтому при изменении стилей компонента может потребоваться обновление каркаса.
- Кривая обучения нелинейна, поскольку есть множество компонентов для различных случаев использования.
Пример
Пример создания скелетного компонента с использованием react-placeholder:
За создание каркасного плейсхолдера отвечает компонент ReactPlaceholder
. Он просто оборачивает нужный компонент приложения в родительский тег. Визуальное представление мы должны собрать сами из доступных элементов и форм и передать в атрибут customPlaceholder
.
Создаем для этого функциональный компонент GhostPlaceholder
. Внутри него используем элементы TextBlock
(блок текста) и RectShape
(прямоугольник), импортированные из react-placeholder/lib/placeholder
.
Все плейсхолдеры можно настраивать через т.н. пропсы. Например, задать цвет и размер (количество рядов текста) для текстового блока.
Чтобы определить, когда показывать каркас, а когда уже подъехал контент, используется булево свойство ready
компонента ReactPlaceholder
.
Больше информации вы найдете в документации модуля.
React Loading Skeleton
Репозиторий: dvtng/react-loading-skeleton
Загрузка пакета:
Достоинства
- Основан на API, есть один компонент, кастомизируемый через пропсы.
- Можно использовать как отдельный скелетный компонент, так и прямо внутри другого компонента.
- Поддерживает темы и пульсирующую анимацию.
Недостатки
- Отлично подходит для простых плейсхолдеров, но разработка сложных каркасов может быть затруднена.
- Наличие отдельного скелетного компонента может затруднить его обслуживание при изменении дизайна.
Пример
Пример создания скелетного компонента с использованием react-loading-skeleton:
Здесь мы импортируем основной компонент Skeleton
и компонент темы SkeletonTheme
из модуля.
Создаем функциональный компонент SkeletonComponent
. SkeletonTheme
служит оберткой для всего элемента и принимает в пропсах цвета (color
, highlightColor
), которые следует использовать в оформлении плейсхолдеров и создании эффектов. Внутри него располагается компонент Skeleton
, размеры которого мы задаем с помощью пропсов width
и height
.
Рассмотрим этот модуль подробнее: разработаем с его помощью скелетный экран YouTube.
Каркасные экраны в стиле YouTube
Установка React
Самый простой способ установить и настроить React в новом приложении – использовать утилиту Create React App. При этом вам почти ничего не придется делать – только набрать команду в терминале. Сначала установите модуль глобально, если вы этого еще не сделали:
Затем создайте новый проект skeleton-screens
:
Когда установка завершится, перейдите в папку проекта и запустите локальный сервер:
Вы увидите приветственный экран React:
Создание интерфейса
Вместо реальных данных с YouTube мы будем использовать заранее подготовленный массив, чтобы не усложнять руководство дополнительной логикой.
Создайте файл data.js
в папке src
и скопируйте туда следующий код:
В этом фрагменте описаны два блока страницы – "Рекомендованное" и "Последние новости" – каждый из которых содержит несколько видео-превью.
Теперь используем эти данные для верстки интерфейса. Нам потребуется три компонента:
Card
– превью видео. Содержит миниатюру видео, его название, количество просмотров, название канала и дату публикации.CardList
– группа превью.App
– корневой компонент приложения. Он получает объектdummyData
, показывает каркасный экран в течение двух секунд, имитируя загрузку данных, а затем отображает компонентCardList
.
Создадим папку components
внутри src
– в ней будем размещать файлы компонентов.
Card
Создайте файл Card.js
в папке components
:
Простой функциональный React-компонент, который выводит данные в шаблон.
CardList
Файл components/CardList.js
:
Этот код еще проще – он выводит на экран массив превьюшек Card
.
App
Наконец, откройте файл App.js
, который уже создан при инициализации проекта и обновите в нем код:
Этот компонент сложнее, так как он имеет собственное состояние.
Мы используем хук useState
, чтобы хранить список видео, а также состояние загрузки.
Хук useEffect
используется для имитации загрузки данных с сервера с задержкой: старый-добрый setTimeout. Только вместо реальных данных мы сохраним заранее подготовленный массив из файла data.js
.
После "загрузки" выводим отдельно каждый блок видео с помощью метода videos.map
. Массив карточек передается в атрибуте list
компоненту CardList
, который отвечает за его визуализацию.
Пока в шаблоне не используется переменная loading,
скоро мы к ней вернемся.
Стилизация
До сих пор мы только расставляли классы в верстке, но не добавляли реальные стили для них. Пора облагородить внешний вид приложения. Откройте файл App.css
в папке src
и замените код на следующий:
Теперь можно посмотреть как выглядит интерфейс, пока без каркасных экранов. Пару секунд, когда страница загружается, мы видим белый экран, а затем все данные появляются сразу.
Подключение React Loading Skeleton
В React Loading Skeleton вам не нужно пошагово создавать скелетный экран, тщательно подбирая параметры типографики, отступы и прочие стили под ваш контент. Его можно поместить прямо внутрь вашего компонента вместо загружаемого контента.
У этой библиотеки есть пара полезных плюшек: легкая темизация и указание продолжительности цикла анимации.
Темы
React Loading Skeleton поддерживает простую настройку тем. Вы можете легко поменять стиль сразу всех скелетных экранов, внеся изменения только в одном месте. За это отвечает компонент SkeletonTheme
.
Продолжительность
Помимо очевидных пропсов height
, width
и color
, мы можем также указать свойство duration
.
По умолчанию оно равно 1.2
. Это значение определяет продолжительность одного цикла анимации экрана.
Больше информации о настройках компонента вы можете найти в документации.
Установка пакета
Чтобы подключить библиотеку react-loading-skeleton
в проект, запустите следующую команду:
Создание компонента
Теперь можно добавить каркасные экраны для видео-данных. В папке components
создайте новый компонент SkeletonCard.js
:
Здесь мы создаем неупорядоченный список и заполняем его элементами (li
) с помощью метода Array.fill()
. Всего элементов 9: по количеству видеороликов в массиве dummyData
, которые будут выведены на страницу после загрузки.
Чтобы вспомнить, как работает метод Array.fill, загляните в документацию на MDN. Нам сейчас важно только, что он создает массив с 9 элементами, которые мы можем проитерировать и с помощью метода Array.map
превратить в массив элементов li
.
Итак, для каждого фейкового видео у нас уже есть каркас, состоящий из нескольких блоков. Пропсы height
и width
отвечают за размеры блока, а circle={true}
формирует круглый блок.
По умолчанию для компонента React Loading Skeleton подключена симпатичная пульсирующая анимация. При желании вы можете создать свою анимацию, мы же воспользуемся дефолтной.
Осталось только подключить каркасный экран в приложение и отображать его, пока происходит подгрузка данных. Внесите изменения в код компонента App
:
Весь исходный код вы можете найти в репозитории проекта.
Наше приложение полностью готово. При открытии отображается красивый каркасный экран с пульсирующей анимацией, а в это время за кадром подгружаются данные. Как только мы их получим (на демо-примере стоит задержка в 5 секунд), то сразу выведем на страницу.
Вот так выглядит результат:
Заключение
Каркасные или скелетные экраны значительно улучшают пользовательский опыт. Они избавляют посетителей сайта от растерянности и непонимания происходящего, а также создают впечатление, будто контент уже на подходе и вот-вот его покажут.
Для создания подобного интерфейса можно использовать готовые библиотеки или реализовать его самостоятельно с помощью простых геометрических фигур и капли анимации.
Какой паттерн для загрузки контента предпочитаете вы?