~/wiki / ux-i-interfeisy / sostoyaniya-interfeysa-empty-loading-error-success

Четыре состояния интерфейса, про которые забывают 90% дизайнеров

Основной чат

Чат для вайбкодеров: новости, гайды, поиск исполнителей, маркетплейс и разбор реальных кейсов.

$ cd раздел/ $ join vibe dev
Четыре состояния интерфейса, про которые забывают 90% дизайнеров - обложка

Откройте любой свежий макет в Figma — главный экран продукта, дашборд, лента. С вероятностью почти в единицу там нарисовано одно состояние: всё хорошо, данные есть, пользователь залогинен, интернет работает, сервер ответил за 200 мс. Идеальный сценарий, который в проде встречается у меньшинства сессий.

А теперь откройте тот же продукт в реальности. Первый запуск без данных. Долгая загрузка на 3G. Поиск, который ничего не нашёл. Форма, которая не отправилась. И вот тут начинается настоящий UX — тот, по которому пользователь решает, остаться ему или закрыть вкладку.

Четыре состояния, про которые забывают почти все: пустое, загрузочное, ошибочное и частичное. Они не баги фронтенда, не «допилит разработчик», не «потом нарисуем». Это полноценные экраны, которые видит больше людей, чем главную фичу продукта.


Почему эти состояния выпадают из работы

Дело не в лени дизайнеров. Дело в том, как устроен процесс.

Макет делается под презентацию: стейкхолдеру надо показать ценность, не пустоту. Дизайн-ревью идёт по «happy path», потому что так быстрее. В дизайн-системе компоненты лежат в состоянии default — и копипастятся в макет именно такими. Разработчик, не получив макета на ошибку, ставит дефолтный alert браузера или серый текст «Something went wrong».

В итоге проблема всплывает не на этапе дизайна, а в проде — через жалобы в поддержку, drop-off в аналитике и фразу «у меня ничего не работает» в отзывах.

Кто реально видит эти состояния

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

Если сложить эти сегменты, окажется, что «идеальный сценарий» — это, наоборот, исключение. И проектировать только под него — значит проектировать продукт для меньшинства сессий.


Состояние 1: Пустое (empty state)

Пустое состояние — это не «ничего нет». Это первый разговор продукта с пользователем без поддержки данных. Тут не от чего оттолкнуться: нет карточек, нет графиков, нет ленты. Остаётся только дизайн.

Три типа пустых состояний

Их часто валят в одну кучу, и это первая ошибка.

  • First-use empty — пользователь только зашёл, данных ещё не может быть в принципе. Сюда нужны онбординг-подсказки, образец, кнопка «создать первое».
  • User-cleared empty — пользователь сам всё удалил, выполнил все задачи, закрыл все тикеты. Тут уместно поздравить, а не пугать пустотой.
  • No-results empty — поиск или фильтр не нашли ничего. Это самое опасное: легко принять за поломку.

Один экран «упс, ничего нет» на все три случая — антипаттерн. Контекст разный, реакция пользователя разная, текст и действие должны быть разными.

Анти-паттерны, которые встречаются на ревью

  • Иллюстрация-маскот и текст «Здесь пока пусто» — без подсказки, что делать.
  • Кнопка «Создать» спрятана в правом верхнем углу, а в центре экрана — только картинка.
  • В no-results нет ни сброса фильтров, ни подсказки «попробуйте другой запрос».
  • Одинаковый экран для первого входа и для случая, когда юзер выполнил все задачи.
  • Текст в духе «No data available» — машинный, не объясняющий.

Что должно быть на экране пустого состояния

  • Чёткое объяснение, почему пусто (не «нет данных», а «вы ещё не добавили ни одного клиента»)
  • Одно главное действие — кнопка или ссылка, ведущая из пустоты
  • Подсказка-пример: как будет выглядеть, когда данные появятся
  • Для no-results — способ сбросить фильтры или изменить запрос
  • Тон голоса, совпадающий с остальным продуктом, без «упс» там, где его нет в бренде

Вопросы для ревью пустого состояния

  • Пользователь, увидев этот экран, понимает, продукт сломался или так задумано?
  • Какое следующее действие очевидно? Оно одно или их несколько?
  • Если бы экран увидел человек, попавший сюда случайно, он бы понял, зачем сюда идти?

Состояние 2: Загрузка (loading state)

Загрузка — это не «пока ничего нет, потерпите». Это полноценное состояние интерфейса, в котором пользователь проводит ощутимую часть времени. И именно здесь чаще всего ломается ощущение скорости продукта — даже если бэкенд быстрый.

Скорость восприятия vs. скорость API

Пользователь не измеряет миллисекунды. Он измеряет, дёрнулся ли интерфейс после клика, появился ли отклик, видно ли прогресс. Запрос на 800 мс с моментальным скелетоном ощущается быстрее, чем запрос на 300 мс с замершим экраном.

Поэтому работа с загрузкой — это в первую очередь работа с обратной связью, и только во вторую — с самим временем ответа.

Чем заменить бесконечный спиннер

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

Что работает лучше в зависимости от контекста:

  • Скелетоны — для лент, карточек, дашбордов. Показывают будущую структуру, снижают ощущение пустоты.
  • Прогресс-бар — когда длительность известна или предсказуема: загрузка файла, импорт, генерация отчёта.
  • Оптимистичный UI — лайк, добавление в корзину, переименование. Действие показывается сразу, откат — только при ошибке.
  • Поэтапная загрузка — сначала каркас, потом основной контент, потом второстепенный. Пользователь начинает работать раньше.

Анти-паттерны загрузки, которые ловятся на ревью

  • Спиннер без таймаута: висит, пока пользователь не закроет вкладку.
  • Скелетон не совпадает по геометрии с финальным контентом — после загрузки экран дёргается, кнопки смещаются, по ошибке нажимается не то.
  • Прогресс-бар скачет назад или замирает на 95% (этот пункт особенно ненавидят за инсталлерами).
  • Оптимистичный UI без отката: пользователь видит, что лайк поставился, а на сервере его нет — и при перезаходе всё пропадает.
  • Загрузка блокирует весь экран, включая навигацию. Если ответ пришёл с ошибкой, пользователь даже выйти не может, кроме как через закрытие вкладки.
  • Прелоадер логотипа на пять секунд только потому, что «так красивее».

Чеклист состояния загрузки

  • Любой клик даёт визуальный отклик в первые 100 мс — хотя бы изменение состояния кнопки
  • Если ответ дольше 1 секунды — показываем что-то структурное, не точку в центре
  • Если дольше ~10 секунд — есть прогресс и понятное «что мы сейчас делаем»
  • Скелетон совпадает по высоте и сетке с реальным контентом
  • Есть путь, если запрос упал: переход в состояние ошибки, а не вечный спиннер
  • Навигация и второстепенные блоки не блокируются загрузкой одного виджета

Вопросы для ревью состояния загрузки

  • Что пользователь видит ровно в первые 200 мс после клика?
  • Если запрос завис на 30 секундах, как выглядит экран?
  • Можно ли начать читать или работать с одной частью страницы, пока грузится другая?
  • Сколько раз пользователю показывают спиннер за один сценарий? Если больше двух — флоу спроектирован «по ручкам», а не по задаче.

Состояние 3: Ошибка (error state)

Ошибка — состояние, которое в макетах рисуется последним, на тоненького, часто уже после релиза. Поэтому в большинстве продуктов оно выглядит как наспех приклеенный модуль: красный текст, восклицательный знак, кнопка «Попробовать снова». А ведь именно в момент ошибки пользователь решает, доверять ли продукту дальше.

Четыре типа ошибок, которые путают

  • Системные — упал сервер, нет интернета, таймаут. Пользователь не виноват, и текст должен это признавать.
  • Пользовательские — невалидный email, слабый пароль, неверный формат файла. Здесь нужно объяснение и пример, как правильно.
  • Бизнес-ограничения — кончился лимит, нет прав, истёк тариф. Это не ошибка в техническом смысле, но интерфейсно ощущается так же. Нужен путь решения: апгрейд, запрос доступа, контакт с админом.
  • Тихие — часть данных не подгрузилась, но интерфейс молчит. Самый коварный тип: пользователь принимает решение на неполной картине.

Один шаблон ошибки на все четыре случая — главная причина, почему ошибки в продукте звучат как робот.

Анти-паттерны ошибок

  • «Что-то пошло не так. Попробуйте позже» — без вариантов, без контекста, без понимания, у кого проблема.
  • Технический stacktrace или код 500 без перевода на человеческий.
  • Toast с ошибкой исчезает за 2 секунды, и пользователь не успевает прочесть, что произошло.
  • Поле формы краснеет, но не объясняет, что именно не так.
  • Кнопка «Повторить» отправляет весь длинный флоу с нуля, теряя введённые данные.
  • Полноэкранная ошибка на временный сбой одного виджета — пользователь не может пользоваться остальным продуктом.

Чеклист состояния ошибки

  • Текст объясняет, что произошло, на языке пользователя, без кодов
  • Понятно, что делать прямо сейчас: повторить, изменить ввод, обратиться в поддержку
  • Введённые данные сохраняются — повтор не стоит пользователю работы
  • Различимы временные ошибки (можно подождать) и постоянные (нужно действие)
  • Ошибка локализована: ломается виджет — не ломается весь экран
  • У важных ошибок есть путь к человеку: чат, email, ссылка на статус

Вопросы для ревью состояния ошибки

  • Сможет ли пользователь решить проблему, опираясь только на текст?
  • Что теряется, если он нажмёт «Повторить» — данные формы, прогресс, контекст?
  • Понятно ли по тону, что виноват продукт, а не пользователь — в тех случаях, когда это так?
  • Если ошибка повторяется три раза подряд, что происходит дальше: бесконечная петля или путь к поддержке?

Как встроить ошибки в рабочий процесс

Самая частая причина плохих ошибок — они рисуются отдельно от основного флоу, в конце спринта, без участия копирайтера и разработчика. Что меняет картину:

  • Каждый макет ключевого экрана сразу едет в Figma тройкой: пустое, загрузка, ошибка. Не «потом доделаем».
  • Тексты ошибок пишутся вместе с UX-копирайтером или хотя бы по словарю тона, а не разработчиком в момент интеграции.
  • На ревью обязательный пункт — «покажи, как этот экран выглядит, если API ответил 500». Если ответа нет, макет не принимается.

Это не утя

желение процесса. Это сдвиг: ошибки перестают быть «довеском к макету» и становятся частью самого экрана.


Состояние 4: Частичные данные (partial state)

Четвёртое состояние почти никогда не появляется в макетах. А в продакшене оно встречается чаще, чем кажется: что-то загрузилось, что-то — нет. Часть карточек получила превью, часть — заглушки. Виджет статистики ответил, виджет рекомендаций молчит. Пользователь видит экран, который технически «работает», но картина неполная.

Где это состояние ловится

  • Дашборды с независимыми блоками: один источник упал, остальные живы.
  • Списки с дочерними запросами на каждый элемент (аватары, статусы, теги).
  • Real-time данные: соединение прервалось, последние 30 секунд — серая зона.
  • Оффлайн-режим: видны кэшированные данные, но не последние.

Анти-паттерны

  • Экран показывает данные, но нигде не помечено, что часть из них устарела или не подгрузилась.
  • Заглушка элемента визуально неотличима от пустого значения — пользователь думает, что «там действительно ноль».
  • При обрыве real-time соединения цифры замораживаются без индикации, и человек принимает решения по старым числам.
  • Кэш в офлайне не имеет таймстампа: непонятно, актуально это или вчерашнее.

Чеклист частичного состояния

  • У каждого блока есть собственное состояние загрузки и ошибки, не общее
  • Видно, какие данные свежие, какие — из кэша, какие не подгрузились
  • Заглушки элементов отличимы от «настоящего ноля»
  • При потере соединения интерфейс честно об этом говорит, а не делает вид
  • Действия, которые зависят от непогруженных данных, заблокированы или предупреждают

Продвинутые сценарии: состояния в комбинации

Жизнь интерфейса — это не «одно состояние за раз». Реальный экран чаще всего смешанный: список загружен, но пуст; данные пришли, но устарели; форма отправлена, но часть полей вернулась с ошибкой. Полезное упражнение на ревью — построить матрицу: каждый блок экрана × четыре состояния. Сразу видно, какие клетки команда никогда не прорабатывала.

Длинные операции

Если операция идёт больше нескольких секунд, четыре состояния превращаются в пять: добавляется прогресс. Признаки, что прогресс сделан правильно:

  • Видно, что система действительно работает, а не зависла
  • Есть оценка времени или этап («3 из 7: обработка изображений»)
  • Можно отвлечься: уведомление вернёт обратно
  • Отмена не оставляет данные в полусломанном состоянии

AI-фичи: те же четыре состояния, новые риски

AI-интерфейсы ломают привычные шаблоны состояний, и команды это часто пропускают.

  • Пусто. В чате с ассистентом «пусто» — это не «нет данных», а «нет контекста». Хороший пустой экран AI-фичи показывает примеры запросов под конкретную роль пользователя, а не абстрактное «Спросите что-нибудь».
  • Загрузка. Спиннер на 20 секунд в ответе LLM — это провал. Стриминг токенов воспринимается быстрее, даже если общее время то же самое. Важно показывать, что модель думает, а не что приложение зависло.
  • Ошибка. К системным и пользовательским добавляется новый тип: низкая уверенность модели или фактическая галлюцинация. Интерфейс должен уметь сказать «я не уверен» — кнопкой «проверить источник», маркером confidence, ссылкой на исходные данные.
  • Частично. Модель ответила на часть запроса, по части — отказалась или не нашла. Это нужно показывать честно, а не склеивать в один уверенный ответ.

Риски, которые стоит обсудить с командой

  • Стриминг может маскировать ошибку: текст начал генерироваться, потом оборвался — пользователь видит обрубок.
  • Кнопка «Повторить» в AI-фиче — это не тот же повтор, что в обычной форме: ответ будет другим. Это надо проговаривать в UI.
  • Автогенерация в Figma/MCP плагинах часто выдаёт только «идеальный» макет. Состояния пусто/загрузка/ошибка/частично приходится дорисовывать руками — заложите это в оценку.

Как встроить четыре состояния в командный процесс

Definition of Done для экрана

Экран считается готовым, только если в Figma есть:

  • Идеальное состояние с реальными данными, не lorem
  • Пустое — для нового пользователя и для отфильтрованного результата
  • Загрузка — короткая и длинная, с прогрессом если нужно
  • Ошибка — системная, пользовательская, бизнес-ограничение
  • Частичное — где данные приходят из разных источников

Вопросы на дизайн-ревью

  • Покажи этот экран в день первого входа — без данных, без истории.
  • Покажи этот экран на медленном 3G.
  • Покажи этот экран, если API ответил 500.
  • Покажи этот экран, если половина данных пришла, половина — нет.

Если на любой из вопросов нет ответа в макете — макет не принят. Не «доделаем потом», а буквально не принят.

Как объяснить это команде

Самый рабочий аргумент — не «так правильно по UX», а деньги и время. Каждое непродуманное состояние превращается в баг в проде, тикет в поддержку, ночной фикс разработчика и косую метрику. Прорисованное состояние — это пять минут в Figma вместо пяти часов на горящем релизе.

Второй аргумент — для продакта: четыре состояния делают видимыми те решения, которые иначе принимает разработчик в одиночку, в три часа ночи, исходя из «как привычнее». А значит, продукт перестаёт расходиться с задумкой в самых нервных точках пользовательского пути.

Анти-паттерны, которые видно на любом ревью

Эти штуки повторяются из проекта в проект независимо от индустрии. Если узнали хотя бы три — это нормально, у всех так. Если ни одного — скорее всего, вы их просто не замечаете.

Спиннер вместо состояния

Самый распространённый. Любая неопределённость закрывается крутящимся кружком: нет данных — спиннер, ошибка сети — спиннер, медленный API — спиннер навсегда. Пользователь не понимает, грузится ли что-то, сломалось ли, или ему вообще нечего ждать.

Пустой экран как заглушка

Серая иллюстрация, надпись «Здесь пока ничего нет» и всё. Ни объяснения, что должно появиться, ни кнопки, чтобы это создать, ни подсказки, что делать. Особенно больно на главных экранах продукта — там, где новый пользователь принимает решение остаться или уйти.

Toast с текстом «Ошибка»

Красное уведомление, которое исчезает через три секунды, с текстом «Произошла ошибка» или, ещё хуже, «Error 500». Пользователь не успел прочитать, не понял, что сломалось, не знает, потерялись ли его данные. Скопировать текст ошибки в поддержку он тоже не может.

«Успех» там, где успеха нет

Зелёная галочка после нажатия «Сохранить», хотя на сервер ушло три из пяти полей. Формально ответ 200, фактически — частичное состояние, которое замаскировано под идеальное. Через неделю поддержка получает жалобу «я же сохранил, а ничего не сохранилось».

Состояния, которые видит только дизайнер

Макет нарисован, в Storybook лежит, в Figma подписан — но в проде его не вызывает ни один реальный сценарий. Либо разработчик не нашёл его в спецификации, либо условие не сматчилось, либо фича-флаг закрыл. Состояние есть на бумаге и нет в продукте.

Расширенный чеклист перед мерджем

Это не дублирует Definition of Done из раздела выше — это последняя проверка уже собранной фичи, перед тем как её увидит пользователь.

  • Прошёл флоу с чистым аккаунтом, без истории и без данных
  • Прошёл флоу при отключённом интернете и при медленной сети
  • Намеренно сломал один из API-вызовов через DevTools — увидел адекватное сообщение
  • Открыл экран на минимальной ширине и на 4K — состояния не поплыли
  • Проверил состояния с длинными именами, длинными списками, эмодзи и иероглифами
  • Скриншоты всех состояний приложены к задаче — не только идеального
  • Тексты ошибок прошли через редактора или хотя бы перечитаны вслух
  • Аналитика стреляет на каждое состояние, не только на успех

Вопросы для глубокого ревью

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

По данным

  • Что произойдёт, если данные пришли, но в неожиданном формате?
  • Что увидит пользователь, у которого данных в десять раз больше, чем у среднего?
  • Как ведёт себя экран, если данные пришли с задержкой уже после того, как пользователь ушёл с него?

По времени

  • Что показывается в первые 200 мс, пока ещё ничего не загрузилось?
  • Что происходит, если загрузка длится 30 секунд вместо ожидаемых трёх?
  • Что увидит пользователь, который вернулся на экран через сутки с открытой вкладкой?

По действиям

  • Что происходит, если пользователь нажал кнопку дважды?
  • Что происходит при отмене посередине операции?
  • Что увидит пользователь, у которого пропали права доступа прямо во время работы?

По доверию

  • На каком состоянии пользователь сильнее всего сомневается, что система работает?
  • Где в интерфейсе он может подумать «я что-то сломал» и закрыть вкладку?
  • Где ему точно нужно подтверждение, что его действие дошло?

Практический итог

Четыре состояния — это не теория и не красивый чеклист в Figma. Это способ перестать сдавать макеты, которые в проде превращаются в баги, нервные созвоны и потерянных пользователей.

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

Дальше — встройте это в процесс: добавьте в Definition of Done, задавайте четыре вопроса на каждом ревью, отказывайтесь принимать макет, где есть только «идеал». Через пару месяцев команда перестанет об этом думать как о чек-листе — это станет нормой. И именно с этого момента продукт начинает ощущаться как сделанный взрослыми людьми, а не как красивая презентация, которая сломалась при первом же реальном пользователе.

$ cd ../ ← назад к UX и интерфейсы