Состояния загрузки и ожидания
1) Зачем управлять ожиданием
Пользователь должен понимать три вещи:- (1) что действие началось, (2) сколько это займет и (3) что делать, если что-то пошло не так.
- Хорошее состояние загрузки снижает тревогу, удерживает фокус и экономит время.
2) Выбор паттерна: skeleton, progress, spinner, streaming
Skeleton — когда известна структура будущего контента, но нет данных. Предотвращает CLS.
Progress bar (детерминированный) — когда известен объем или этапы (например, аплоад, KYC).
Indeterminate progress — когда длительность неизвестна, но процесс реальный (инициализация).
Spinner — только как краткий индикатор до 600–800 мс; дальше — skeleton/прогресс/текст.
Streaming/partial render — отдаем данные частями (SSR/сегменты) и показываем готовые зоны сразу.
Правило: не оставляйте пользователя на «пустом месте». Если больше 1 с — дайте структуру и смысл.
3) Временные пороги и бюджеты (ориентиры)
≤ 100 мс — мгновенный визуальный отклик: `busy` на кнопке/поле.
≤ 1000 мс — skeleton/индикатор + текст «Загружаем…».
10 с — эскалация: предложение «Продолжить в фоне», уведомление, лог о статусе.
4) Микро-паттерны мгновенного отклика
Переводим контрол в `busy` сразу (анимация ≤ 100 мс), блокируем повторные клики.
Текст кнопки меняем на «Отправляем…», показываем тост «Запрос принят» (опционально).
При возврате фокуса на поле — локальный skeleton в зоне результата.
5) Skeleton без «скачков»
Рисуйте 1:1 форму будущего контента: высоты блоков, пропорции медиа (`aspect-ratio`).
Анимация shimmer: 1200–1600 мс, амплитуда яркости ≤ 20%, без строба.
На больших списках — виртуализация + ограничение количества скелетонов в DOM.
css
.skeleton{position:relative; background:var(--bg-elevated); border-radius:12px; overflow:hidden}
.skeleton::after{
content:"";position:absolute; inset:0;
background:linear-gradient(90deg,transparent,rgba(255,255,255,.1),transparent);
animation:shimmer 1. 4s infinite;
}
@keyframes shimmer{from{transform:translateX(-100%)}to{transform:translateX(100%)}}
6) Прогресс и этапы