Обратная связь
Скелетон
Место, где содержимое ещё не пришло. Кит про ожидание обязан иметь примитив ожидания содержимого.
Разметка
<div class="inst-stack inst-stack--tight">
<div class="inst-skeleton inst-skeleton--title"></div>
<div class="inst-skeleton inst-skeleton--line"></div>
<div class="inst-skeleton inst-skeleton--short"></div>
</div>
Использование
<div class="inst-stack inst-stack--tight" aria-busy="true">
<div class="inst-skeleton inst-skeleton--title"></div>
<div class="inst-skeleton inst-skeleton--line"></div>
<div class="inst-skeleton inst-skeleton--short"></div>
</div>
| Что | Обязательно | Почему |
|---|---|---|
aria-busy="true" на контейнере |
да | Скелетон — оформление, а не роль. Без атрибута для скринридера страница просто пуста |
inst-skeleton на каждой полосе |
да | База: поверхность, радиус, пульсация, высота 1lh |
| Форма повторяет будущее содержимое | да | Скелетон не той формы врёт дважды |
Высота 1lh — реальная высота строки текущего кегля. Поэтому скелетон занимает
ровно столько же, сколько займёт пришедший текст, и при подмене ничего не
прыгает.
Когда использовать
| Используйте | Возьмите другое |
|---|---|
| Известна форма будущего содержимого: заголовок и три строки | Форма неизвестна или ожидание короче секунды — спиннер: скелетон не той формы врёт дважды |
| Ожидание внутри блока, который уже занимает место | Ожидание, занявшее весь экран — спиннер с подписью: полотно из серых полос не сообщает ничего |
| Данных ещё нет | Данных нет и не будет — пустое состояние: скелетон в этот момент обещает то, чего не случится |
| Догрузка части вида | Прогресс с известной долей — мера: у неё есть число |
Варианты
Разметка
<div class="inst-stack inst-stack--tight">
<div class="inst-skeleton inst-skeleton--title"></div>
<div class="inst-skeleton inst-skeleton--line"></div>
<div class="inst-skeleton inst-skeleton--line"></div>
<div class="inst-skeleton inst-skeleton--short"></div>
</div>
| Класс | Ширина | Работа |
|---|---|---|
inst-skeleton |
наследует | База: поверхность, радиус, пульсация. Высота — 1lh |
inst-skeleton--title |
40% |
Заголовок абзаца |
inst-skeleton--line |
100% |
Полная строка текста |
inst-skeleton--short |
62% |
Последняя строка абзаца |
--short в конце — не украшение: настоящий абзац редко заканчивается ровно по
правому краю, и полоса той же длины читается как таблица, а не как текст.
Ширину можно задать и своим правилом — модификаторы лишь три частых значения.
Поведение
Пульсация
Скелетон пульсирует прозрачностью: opacity от 1 до 0.45 и обратно за
1.6с. Ключевые кадры — собственные, бесконечно.
Бегущий блик — это градиент, а градиенты в ките запрещены. Но дело не только в запрете: блик изображает движение слева направо, то есть заполнение, а скелетон ничего не заполняет. Пульсация спокойнее и честнее — блок не притворяется наливающимся.
Композиции
В теле панели
Разметка
<div class="inst-panel">
<div class="inst-panel-header">
<span class="inst-panel-title">Вывод</span>
</div>
<div class="inst-panel-body">
<div class="inst-stack inst-stack--tight" aria-busy="true">
<div class="inst-skeleton inst-skeleton--title"></div>
<div class="inst-skeleton inst-skeleton--line"></div>
<div class="inst-skeleton inst-skeleton--short"></div>
</div>
</div>
</div>
Скелетон повторяет форму того, что придёт. Три полосы на месте трёх строк — это подсказка; двадцать полос на месте карточки с кнопкой — шум.
Правила
Так Форма будущего содержимого
Заголовок и три строки на месте заголовка и трёх строк. При подмене ничего не
прыгает, потому что высота — 1lh.
Не так Полотно из серых полос
Двадцать полос на месте карточки с кнопкой не сообщают ничего. Там, где формы не знают, нужен спиннер с подписью.
Так aria-busy на контейнере
Скелетон — оформление, а не роль. Занятость объявляет область, которая грузится.
Не так Бегущий блик
Он изображает заполнение, а скелетон ничего не заполняет. Плюс это градиент, а градиенты в ките запрещены.
Доступность
| Область должна объявить занятость | Скелетон — оформление, а не роль. Контейнер, который грузится, несёт aria-busy="true", иначе для скринридера страница просто пуста |
| Не читается | Полосы пусты и не содержат текста: скринридеру их читать нечем и не нужно |
| Уменьшенное движение | Пульсация замедляется до 3с, а не гаснет: кит, вся работа которого — показывать занятость машины, обязан показывать её всегда |
| Амплитуда | opacity не опускается ниже 0.45: мигание с большей амплитудой раздражает периферийное зрение |
| Печать | На листе не печатается: печать статична, а ожидание на бумаге бессмысленно |
API
| Имя | Значение | Что делает |
|---|---|---|
| класс | ||
inst-skeleton | — | Базовый. Обязателен всегда |
| модификатор | ||
inst-skeleton--title | — | Ширина 40% |
inst-skeleton--line | — | Ширина 100% |
inst-skeleton--short | — | Ширина 62% |
| токен | ||
--surface-sunken | light-dark(var(--n-2), var(--n-14)) | |
--radius-xs | 3px | |
--ease-in-out | cubic-bezier(0.65, 0, 0.35, 1) | |
Почему кит устроен именно так — конституция · Открытый код под MIT, github.com/keshon/instrument