Скелетон

Скелетон стоит вместо содержимого, пока оно грузится. На статическом сайте такое встречается реже, чем в приложении, — HTML уже на месте, — но именно им обычно и стоит быть fallback-у острова, и именно это показывает область, отрисовываемая на клиенте, пока не пришли её данные.

Скелетоны декоративны: у каждого есть aria-hidden, чтобы скринридеру не зачитывали список пустых коробок.

Формы

stack({ gap: 'md' },
  skeleton({ height: '2.5rem' }),
  skeleton({ variant: 'text', width: '70%' }),
  skeleton({ variant: 'circle', width: '3rem', height: '3rem' }),
)

Текст

lines рисует объём целого абзаца, с короткой последней строкой, чтобы это читалось как текст, а не как блок.

stack({ gap: 'lg' },
  skeleton({ lines: 2 }),
  skeleton({ lines: 4 }),
)

В форме настоящего

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

AL

Ada Lovelace

Отправила 3 коммита
grid({ min: '14rem' },
  card(
    cardBody(
      stack({ gap: 'md' },
        stack({ direction: 'row', gap: 'sm', align: 'center' },
          skeleton({ variant: 'circle', width: '2.5rem', height: '2.5rem' }),
          stack({ gap: 'xs', style: 'flex: 1' },
            skeleton({ variant: 'text', width: '60%' }),
            skeleton({ variant: 'text', width: '40%' }),
          ),
        ),
        skeleton({ lines: 3 }),
      ),
    ),
  ),
  card(
    cardBody(
      stack({ direction: 'row', gap: 'sm', align: 'center' },
        avatar({ name: 'Ada Lovelace' }),
        stack({ gap: 'none' },
          text({ variant: 'small' }, 'Ada Lovelace'),
          text({ variant: 'caption', tone: 'muted' }, 'Отправила 3 коммита'),
        ),
      ),
    ),
  ),
)

Как запасной вариант острова

Серверный остров отгружает свой запасной вариант прямо в статическом HTML, а в момент запроса подменяет его отрендеренным фрагментом. Скелетон той же формы, что и фрагмент, не даёт странице прыгнуть, когда тот приедет.

Комментарии

card(
  cardHeader({ title: 'Комментарии' }),
  cardBody(
    stack({ gap: 'md' },
      skeleton({ lines: 2 }),
      divider({ spacing: 'xs' }),
      skeleton({ lines: 2 }),
    ),
  ),
)

Движение

Мерцание останавливается для тех, кто попросил систему уменьшить движение: это решается в таблице стилей, и никакого пропа задавать не нужно.

Пропсы

ПропТипПо умолчаниюОписание
variant'rect' | 'text' | 'circle''rect'Форма заглушки.
widthstring—Любая CSS-ширина.
heightstring—Любая CSS-высота.
linesnumber—Нарисовать столько строк текста, последнюю — короткой.