Создавайте каркасные экраны с пользовательскими свойствами CSS

внешний интерфейс Vue.js React.js CSS

написать впереди

Несколько дней назад я увидел «поделился фронтенд-командой Mint».Краткое изложение решения каркасного экрана переднего плана", вдруг вспомнилось "макс бок", написанное максом боком, которое я видел год назадBuilding Skeleton Screens with CSS Custom Properties", перевел и систематизировал эту статью и поделился навыками использования пользовательских свойств CSS для создания экрана-скелета. Давайте сначала посмотрим на демонстрационный эффект экрана-скелета.


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


иллюзия скорости

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

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

Для веб-приложений эта концепция может включать «модели», которые отображают текст, изображения или другие элементы содержимого, называемые
Скелетонный экран💀. Можно увидеть в Интернете, Facebook, Google, Slack и т. Д. Используйте:


(Скелетный экран Facebook)


(скелетный экран Slack)

пример

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


Вы можете сжать карту до ее основной визуальной формы (каркас компонента пользовательского интерфейса).


Всякий раз, когда кто-то запрашивает новый контент с сервера, вы можете сразу начать показывать скелет при загрузке данных в фоновом режиме. Как только контент будет готов, просто замените скелет на настоящую карту. Это можно сделать с помощью простого JavaScript или с помощью библиотеки, такой как Vue/React.

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

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

Рисование скелетов с помощью CSS

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

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

.skeleton {
  background-repeat: no-repeat;
  background-image:
    radial-gradient(circle 16px, white 99%, transparent 0), /* 第3层 头像 */
    linear-gradient(white 40px, transparent 0), /* 第2层 标题 */
    linear-gradient(gray 100%, transparent 0); /* 第1层 卡片背景 */
}

Эти фигуры растягиваются, чтобы заполнить пространство, как обычные элементы блочного уровня. Если мы хотим изменить его, мы должны определить для них явные размеры.background-sizeзначения для установки ширины и высоты каждого слоя, сохраняя тот же порядок, который мы использовалиbackground-image:

.skeleton {
  background-size:
    32px 32px,  /* 头像 */
    200px 40px,  /* 标题 */
    100% 100%; /* 卡片背景 */
}

Завершающим этапом является размещение элемента на карточке. Это похоже на position:absolute, означающее, что свойства left и top имеют одинаковое значение. Например, мы можем имитировать отступы в 24 пикселя для аватаров и заголовков, чтобы они соответствовали внешнему виду реальных карточек контента.

.skeleton {
  background-position:
    24px 24px,  /* 头像 */
    24px 200px, /* 标题 */
    0 0;        /* 卡片背景 */
}


Разбейте его с помощью настраиваемых атрибутов

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

Поэтому предлагается использовать пользовательские свойства CSS для написания стилей скелета более лаконичным и удобным для разработчиков интерфейса образом и даже учитывать взаимосвязь между различными значениями:

.skeleton {
  /*
    定义单独的属性
  */
  --card-height: 340px;
  --card-padding:24px;
  --card-skeleton: linear-gradient(gray var(--card-height), transparent 0);

  --title-height: 32px;
  --title-width: 200px;
  --title-position: var(--card-padding) 180px;
  --title-skeleton: linear-gradient(white var(--title-height), transparent 0);

  --avatar-size: 32px;
  --avatar-position: var(--card-padding) var(--card-padding);
  --avatar-skeleton: radial-gradient(
    circle calc(var(--avatar-size) / 2), 
    white 99%, 
    transparent 0
  );

  /* 
    现在我们可以把背景分解成单独的形状
  */
  background-image: 
    var(--avatar-skeleton),
    var(--title-skeleton),
    var(--card-skeleton);

  background-size:
    var(--avatar-size),
    var(--title-width) var(--title-height),
    100% 100%;

  background-position:
    var(--avatar-position),
    var(--title-position),
    0 0;
}

Это не только более читабельно, но и позволяет позже изменить некоторые значения. Кроме того, мы можем использовать некоторые переменные (например, размер аватара, отступы карты), чтобы определить стиль фактической карты и всегда синхронизировать ее со скелетной версией. Добавление медиа-запроса для настройки частей скелета для разных точек останова теперь также очень просто:

@media screen and (min-width: 47em) {
  :root {
    --card-padding: 32px;
    --card-height: 360px;
  }
}

ps: Браузерная поддержка пользовательских свойств хороша, но не на 100%. В принципе, все современные браузеры поддерживают, IE/Edge немного запаздывает. Для этого конкретного случая использования легко добавить запасные варианты, используя переменные Sass.

Добавить анимацию

Чтобы сделать это еще лучше, мы можем анимировать наш скелет и сделать его более похожим на индикатор загрузки.
Все, что нам нужно сделать, это поместить новый градиент сверху и использовать его для анимации его положения.@keyframes
Ниже приведен полный вид готовой карты-скелета.Скрин-демонстрация скелета:


Конечно, вы можете использовать селектор :empty и псевдоэлементы для рисования скелета.Таким образом, это работает только для пустых элементов карты, как только содержимое вводится, экран кадра автоматически исчезает..

Наконец, заинтересованные студенты могут зайти на мой github, чтобы загрузить этоSkeleton screen-демонстрационный портал с исходным кодом