Состояния загрузки: спиннеры, скелетоны и прогресс-бары
Практика3 минРедакция Innovialabs
Коротко
Индикатор загрузки выбирают по ожидаемому времени ожидания: до секунды — ничего, несколько секунд — скелетон или спиннер, дольше — прогресс-бар с понятным статусом. Плюс обязательно продумывают ошибку, таймаут и частичную загрузку.
Какой индикатор выбрать
Главный критерий — сколько ждёт пользователь и известен ли объём работы. Ориентиры, которыми пользуются большинство команд:
| Ожидание | Что показывать |
|---|---|
| Меньше ~1 секунды | Ничего или мгновенная реакция кнопки. Индикатор только мигнёт и создаст ощущение тормозов |
| 1–3 секунды, известна структура экрана | Скелетон — серые блоки на месте будущего контента |
| 1–10 секунд, структура неизвестна или действие точечное | Спиннер на кнопке или в области, которая обновляется |
| Дольше ~10 секунд или известен объём | Прогресс-бар с процентами или шагами и возможностью отмены |
Скелетоны работают на экранах со списками и карточками, спиннеры — на действиях вроде «Сохранить», прогресс-бары — на загрузке файлов, экспорте, импорте и генерации.
Воспринимаемая скорость
Perceived performance — то, насколько быстрым продукт кажется, а не сколько миллисекунд он реально тратит. Его улучшают без ускорения сервера:
- Мгновенная реакция на действие. Кнопка меняет состояние сразу после нажатия, даже если запрос ещё идёт.
- Стабильная раскладка. Скелетон повторяет реальные размеры блоков, поэтому контент не «прыгает» после загрузки.
- Задержка перед индикатором. Если ответ может прийти быстро, спиннер показывают не сразу, а через короткую паузу (обычно 200–500 мс). А если уж показали — держат минимальное время, чтобы не было мерцания.
- Сначала главное. Заголовок и ключевые данные приходят первыми, второстепенное догружается следом.
Оптимистичный UI
Optimistic UI — интерфейс показывает результат действия до ответа сервера. Поставили лайк — сердечко сразу закрасилось, добавили задачу — она уже в списке.
Подходит, когда:
- действие почти всегда успешно (лайк, отметка «прочитано», перестановка карточек);
- его легко откатить.
Не подходит для платежей, отправки заявок, удаления без корзины — там пользователь должен видеть реальный статус.
Обязательная часть паттерна — откат: если сервер вернул ошибку, элемент возвращается в исходное состояние, и пользователь видит понятное сообщение, а не тихо исчезнувшее изменение.
Частичная загрузка
Экран редко грузится целиком за один запрос. Каждый блок должен уметь жить самостоятельно:
- виджеты загружаются независимо, и медленный блок не держит весь экран;
- в длинных списках — подгрузка порциями с индикатором внизу или кнопкой «Показать ещё»;
- изображения резервируют место заранее и показывают заглушку или размытое превью;
- при обновлении уже загруженных данных старый контент остаётся на экране, а индикатор показывают поверх или рядом — не возвращают скелетон.
Ошибки и таймауты
Состояние загрузки без сценария ошибки — незаконченный дизайн. Для каждого блока продумайте:
- Ошибку сети или сервера: что случилось простыми словами и кнопка «Повторить».
- Таймаут: через сколько секунд перестать ждать и что сказать пользователю. Бесконечный спиннер — худший вариант.
- Долгое ожидание: если операция затянулась, обновите текст («Ещё немного, обрабатываем файл»), чтобы было видно, что процесс жив.
- Пустое состояние: загрузка прошла успешно, но данных нет. Это отдельный экран, а не ошибка.
- Офлайн: что доступно без сети и что произойдёт с действиями, сделанными в это время.
Как передать разработчикам
Чтобы состояния не придумывали на ходу, опишите их в макетах и спецификации:
- Матрица состояний для каждого экрана и компонента: idle, loading, success, empty, error, partial.
- Тип индикатора для каждого действия и место, где он появляется.
- Тайминги: задержка до показа индикатора, минимальное время показа, таймаут.
- Скелетон-компоненты в дизайн-системе с теми же размерами, что у реальных карточек.
- Тексты для ошибок, таймаутов и долгого ожидания.
- Поведение при ошибке в оптимистичном UI: как выглядит откат.
- Анимации: длительность и отключение при
prefers-reduced-motion.
Частые ошибки
- Спиннер на весь экран при обновлении одного блока.
- Скелетон, который не совпадает с реальной раскладкой.
- Индикатор без таймаута и без сообщения об ошибке.
- Прогресс-бар, который застывает на 99% — лучше честный статус шага.
- Заблокированный интерфейс там, где можно продолжать работу.