Обратная связь
Семь компонентов отвечают на один вопрос — куда идёт сообщение. Ошибка в выборе и есть причина, по которой интерфейс кажется неотзывчивым.
Что решает
Всякое сообщение интерфейса — ответ на вопрос «что сейчас произошло и касается ли это меня». Трудность не в том, чтобы написать текст, а в том, чтобы положить его туда, куда человек уже смотрит, и в тот момент, когда он спрашивает.
Этим заняты семь компонентов, и они не взаимозаменяемы. Каждый отвечает на свой вопрос, и условие для каждого записано в библиотеке:
- Сообщение относится к месту на странице —
GrAlert. Держится, пока не изменится обстоятельство, потому что обстоятельство никуда не делось. - Действие завершилось —
GrToaster. Появился, прочитан, ушёл; на странице ничего не поменяло формы. - Запрос упал —
GrResponseErrorBanner. Берёт сырую ошибку и превращает статусы, разбор валидации и сетевые сбои в заголовок, сообщение и повтор — не зная, что это был за запрос. - Список пуст с самого начала —
GrEmptyState. Это не ошибка: место, куда ещё ничего не положили, и подсказка, что с этим делать. - Контента ещё нет —
GrSkeleton. Форма приезжает раньше данных, и страница не прыгает, когда они приедут. - Контент уже есть и обновляется —
GrLoading. Отличается от скелета: есть на что смотреть, и оно не должно исчезать. - Доля выполненного известна —
GrProgressBar. Только когда действительно известна: полоса, которая гадает, — ложь с числом внутри.
Анатомия
У обратной связи три свойства, и они есть у каждого сообщения — выбирали вы их или нет.
Место. Привязано к тому, о чём говорит, или висит над страницей. Первое —
GrAlert и ошибка внутри поля, второе — GrToaster. Сообщение о конкретном
поле, висящее над страницей, человек сопоставляет сам.
Срок жизни. До закрытия, до изменения обстоятельств или несколько секунд. Правило простое: сообщение, требующее действия, живёт, пока действие не сделано. Тост, несущий единственную возможность отменить, — ловушка с таймером.
Вес. Цвет, иконка и формулировка говорят, насколько всё плохо. Трёх уровней достаточно: нейтральный, предупреждение, ошибка. Четвёртый придумывают те, кто называл ошибкой всё подряд, а потом понадобилось что-то громче.
Пример
Так и не так
Так — Тост о завершившемся, алерт о том, что всё ещё верно
«Сохранено» кончается в момент прочтения — тост. «Проект только для чтения» верно, пока что-то не изменится, — алерт на странице. Вопрос не в важности, а в длительности.
Так не надо — Тост для того, что требует решения
Сообщение, исчезающее по таймеру, не может нести единственную «отмену». Человек, отвернувшийся на секунду, потерял возможность и не знает, что она была. Нужно решение — сообщение остаётся, пока его не примут.
Так — Скелет, когда нет ничего; индикатор, когда есть
GrSkeleton резервирует форму до прихода данных, и ничего не прыгает, когда они
придут. GrLoading говорит, что существующий блок обновляется, — содержимое
остаётся читаемым всё это время.
Так не надо — Крутилка вместо всей страницы
Подменяя содержимое крутилкой, вы выбрасываете то, что человек читал, и не сообщаете, чего ждать. Отличить медленную страницу от сломанной он не может: и то и другое выглядит как кружок.
Так — Говорить, что делать дальше, — особенно в пустоте
Пустой список — вопрос, а не отказ: «счетов пока нет» и кнопка, создающая первый.
GrEmptyState существует потому, что первый экран нового аккаунта — самый частый
экран любого продукта и наименее продуманный.
Так не надо — «Что-то пошло не так»
Не говорит ничего и не предлагает ничего. Сервер прислал статус, а часто и
причину; GrResponseErrorBanner их читает. Если причина и правда неизвестна —
скажите, что человек может сделать: повторить или написать в поддержку, — и
оставьте честную фразу короткой.
Доступность
Появившееся сообщение надо объявить. Тост, который плавно возник и растаял без живой области, для скринридера не существует: действие завершилось, и никто об этом не сказал.
Срочность — свойство сообщения, а не цвета. Настойчивое объявление прерывает то, что читают сейчас: верно для ошибки, которая мешает работать, и неверно для «сохранено». Перебить человека посреди фразы, чтобы сообщить, что всё хорошо, — хуже, чем промолчать.
Загрузка должна восприниматься без движения. Анимированная крутилка ничего не
значит для того, у кого движение выключено, а prefers-reduced-motion — не
редкость. Смысл несут текст и зарезервированное место; анимация его повторяет.
Время показа — единственное, чего за вас не решит ни один компонент. Тост, живущий четыре секунды, нечитаем для того, кто читает медленно, и правильного числа тут нет — поэтому важное не должно от него зависеть.
Компоненты паттерна
Список строится из frontmatter, а не из ссылок в тексте: переименование слага здесь не теряется.
GrAlertОбратная связьGrToasterОбратная связьGrEmptyStateОбратная связьGrSkeletonОбратная связьGrLoadingОбратная связьGrProgressBarОбратная связьGrResponseErrorBannerОбратная связь
Клавиатура
Контракты приходят из библиотеки. Паттерн их не пересказывает — он на них ссылается.
GrToasterКонтракт компонента