GrSkeleton

  • ядро
  • Обратная связь
  • API · 5 props

Берут, когда контента ещё нет.

import { GrSkeleton } from '@feugene/granularity/components/GrSkeleton'

Обзор

Когда брать

  • контента ещё нет — заглушка повторяет его форму, и раскладка не прыгает при появлении данных;
  • загрузка первой отрисовки — карточка, список, таблица: пользователь видит структуру до данных;
  • заглушек несколько — count повторяет строку нужное число раз;
  • форма нестандартная — variant даёт полосу, блок или круг под аватар.

Когда взять другое

НужноБерите
Контент уже есть, но обновляетсяGrLoading
Известна доля выполненногоGrProgressBar
Загрузка закончилась, данных нетGrEmptyState
Ожидание внутри кнопкиGrButton с loading

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

Варианты все тона и виды — настоящим компонентом

variant

  • circle
  • text
  • rect

Playground контролы выводятся из API, а не пишутся руками

Сцена

Загружается…

0 изменено· состояние — в адресе

Примеры 3 у каждого — живое демо и его код

  • Список клиентов, который не прыгает

    Заглушка повторяет настоящую строку — круг под аватар, короткая и длинная линии под имя и адрес, пилюля под тариф, — и каждая строка держит одну высоту в обоих состояниях, поэтому данные сменяют заглушку без прыжка. Заглушки aria-hidden: список объявляет aria-busy, а живая строка говорит, что загрузилось.

    Customers
    Loading customers
  • Карточки справочного центра

    Обложка — блок: variant="rect" со скруглением карточки через rounded, в высоту картинки. Подводка — абзац: :count="2" укорачивает последнюю строку, и блок читается текстом, а не стопкой полос. При prefers-reduced-motion пульсация останавливается совсем.

    Help centre · Billing
    Loading articles
  • Показатели, которые пересчитываются

    Форму даёт variant, размер — показатель, который заглушка подменяет: короткая линия под подпись, блок высотой в число и пилюля под изменение. Каждое место держит высоту строки своего текста, и плитки не сдвигаются, когда приходят цифры.

    October so far
    Recalculating

API порождается из пакета · разойтись не может

Props

PropTypeпо умолчаниюОписание
variant"circle" | "text" | "rect" | undefined"text"Форма, а не размеры: `width`/`height` остаются на потребителе, потому что высота заглушки диктуется соседним контентом, а не шкалой компонента.
countnumber | undefined1Сколько заглушек подряд. Больше одной — они уезжают в общую обёртку.
widthstring | undefinedundefinedШирина, CSS-длина. По умолчанию `100%`, у круга — `2.5rem`; без неё последняя из нескольких текстовых строк короче остальных.
heightstring | undefinedundefinedВысота, CSS-длина. По умолчанию `12px`, у круга — равна ширине.
roundedstring | undefinedundefinedРадиус точечно. Не задан — берётся из `variant`.

Типы

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

Импорт
import type { GrSkeletonProps, GrSkeletonVariant } from '@feugene/granularity/components/GrSkeleton'

Файлdist/types/components/GrSkeleton/GrSkeleton.vue.d.ts

GrSkeletonPropsinterface

GrSkeleton — заглушка-плейсхолдер для загружающегося контента. Помечен aria-hidden="true", чтобы скринридер не озвучивал «пустой» узел; внешний контейнер обычно имеет aria-busy="true" + aria-live.

interface GrSkeletonProps {
    /**
     * Форма, а не размеры: `width`/`height` остаются на потребителе, потому что
     * высота заглушки диктуется соседним контентом, а не шкалой компонента.
     */
    variant?: GrSkeletonVariant;
    /** Высота, CSS-длина. По умолчанию `12px`, у круга — равна ширине. */
    height?: string;
    /**
     * Ширина, CSS-длина. По умолчанию `100%`, у круга — `2.5rem`; без неё последняя из
     * нескольких текстовых строк короче остальных.
     */
    width?: string;
    /** Радиус точечно. Не задан — берётся из `variant`. */
    rounded?: string;
    /** Сколько заглушек подряд. Больше одной — они уезжают в общую обёртку. */
    count?: number;
}

Файлdist/types/components/GrSkeleton/grSkeletonStyles.d.ts

GrSkeletonVarianttype
type GrSkeletonVariant = typeof GR_SKELETON_VARIANTS[number];

Файлdist/types/components/GrSkeleton/config.d.ts

grSkeletonConfigconst
const grSkeletonConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrSkeleton">;

Использование из прозы библиотеки

Форма — вариантом, размеры — потребителем
variantРадиусДля чего
text (по умолчанию)--gr-radius-fullстрока текста
rect--gr-radius-mdблок: карточка, кнопка, картинка
circle--gr-radius-fullаватар, иконка

Вариант задаёт только форму. width и height остаются на потребителе: высоту заглушки диктует контент, который она подменяет, а не шкала компонента. Дефолт — 100% × 12px, у круга — 2.5rem.

Круг — единственная форма, где размеры связаны: height повторяет width, пока её не задали явно. Иначе одна заданная сторона превращала бы круг в овал.

rounded перекрывает радиус варианта точечно — например, когда у карточки приложения свой крупный радиус.

Блок из нескольких строк
vue
<GrSkeleton :count="3" />

count рисует N заглушек в общей сетке. У text последняя строка короче (60%): блок читается как абзац, а не как список одинаковых полос. У rect и circle все элементы одинаковые — «недописанной строки» у них не бывает. Заданный width сильнее этого правила.

Одна заглушка (count по умолчанию) рендерится без обёртки — ровно тем же узлом, что и раньше.

Доступность

Заглушка целиком помечена aria-hidden="true" — и одиночная, и обёртка группы. Озвучивать «пустой» узел незачем; о том, что идёт загрузка, сообщает контейнер: aria-busy="true" и живой регион с текстом. Так это сделано внутри пакета — см. состояние loading у GrStatistic и GrTable.

Движение

Пульсация — собственный @keyframes компонента, и под prefers-reduced-motion: reduce она выключается полностью (animation: none), а не ускоряется: бесконечная анимация — это движение, которого пользователь попросил не показывать. Контракт движения целиком — ../motion.md.

<style> у компонента без scoped намеренно: правило висит на атрибуте [data-gr-skeleton], поэтому доезжает и до заглушек, отрисованных внутри других компонентов пакета.