Уведомления и тосты: что, где и насколько громко сообщать

Пять видов сообщений от тихого к громкому, тост с «Вернуть», где он появляется на телефоне, слова, которые помогают, и одно сообщение вместо пяти — с живыми примерами.

Интерфейс-элементы Обновлено

Коротко

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

От тихого к громкому

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

Какой вид для какого сообщения

Вид выбирают по двум вопросам: видно ли это без сообщения и должен ли человек что-то сделать?

СообщениеВидИсчезает
«Скопировано», «Сохранено» строка у кнопки или тост да, через 4–6 секунд
Удаление, которое можно вернуть тост с «Вернуть» да, но не раньше чем через 7 секунд и не под курсором
Ошибка в форме у поля и списком сверху нет, пока её не исправят
Нет сети, сеанс заканчивается баннер вверху нет, пока проблема есть
Новое сообщение или заказ счётчик на значке когда прочитают
Данные пропадут безвозвратно окно только после ответа

«Вернуть» вместо «Вы уверены?»

Удалите фото и посмотрите на сообщение внизу: у него есть действие, полоска времени, и оно замирает, пока на него наведён курсор.

Фото проекта «Кухня на Лесной»

Фото удалено

Нажмите «Удалить» и наведите курсор на сообщение: пока он там, время стоит. «Вернуть» отменяет удаление — вопрос «Вы уверены?» не понадобился.

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

Где появляется тост

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

Поверх кнопки
Над нижней панелью

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

Что случилось и что делать

Код ошибки помогает разработчику, а не человеку. В хорошем сообщении две части: что произошло и что делать дальше.

Одно сообщение вместо пяти

Пять быстрых добавлений в корзину — пять одинаковых тостов поверх страницы. Одно сообщение с итогом и следующим шагом говорит больше.

Стопка из пяти
Одно, с итогом

Уведомления в коде: 3 примера

Живые области, которые слушает экранная читалка, тост с действием и таймером, который умеет ждать, и стили, которые держат его над нижней панелью.

Живые области

status читается, когда читалка освободится, alert перебивает — только для ошибок. Области стоят на странице с самого начала.

notifications.html
<!-- Тосты: читаются вежливо, не сдвигая фокус -->
<div class="toasts" role="status" aria-live="polite"></div>

<!-- Баннер — для проблемы на всю страницу -->
<div class="banner" role="alert" hidden>
  Нет сети. Изменения сохранятся, когда она вернётся.
</div>

<!-- Результат прямо рядом с действием -->
<button class="button" type="button" data-copy-link>Скопировать ссылку</button>
<span class="copy-result" role="status"></span>

Тост с действием

Таймер останавливается под курсором и фокусом; новое сообщение заменяет старое.

toast.js
const region = document.querySelector('.toasts');

function toast(text, { action, onAction, duration = 7000 } = {}) {
  const item = document.createElement('div');
  item.className = 'toast';
  item.textContent = text;

  if (action) {
    const button = document.createElement('button');
    button.type = 'button';
    button.textContent = action;
    button.addEventListener('click', () => {
      onAction?.();
      item.remove();
    });
    item.append(button);
  }

  // Время стоит, пока на сообщении курсор или фокус
  let timer;
  const start = () => { timer = setTimeout(() => item.remove(), duration); };
  const stop = () => clearTimeout(timer);
  item.addEventListener('mouseenter', stop);
  item.addEventListener('mouseleave', start);
  item.addEventListener('focusin', stop);
  item.addEventListener('focusout', start);

  region.replaceChildren(item);   // по одному: новое сообщение заменяет старое
  start();
}

toast('Фото удалено', { action: 'Вернуть', onAction: restorePhoto });

Место и появление

На телефоне тост стоит над нижней панелью, на компьютере — в левом нижнем углу.

toast.css
/* Если на странице есть липкая панель покупки, её высота поднимает тосты */
body:has(.buy-bar) { --bottom-bar: 4.5rem; }

.toasts {
  position: fixed;
  inset-inline: var(--space-4);
  bottom: calc(var(--space-4) + var(--bottom-bar, 0px) + env(safe-area-inset-bottom));
  z-index: 20;
  display: grid;
  justify-items: center;
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  max-width: 28rem;
  padding: var(--space-3) var(--space-3) var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--color-surface-inverse);
  color: var(--color-text-inverse);
  pointer-events: auto;
  animation: toast-in var(--duration-base) ease-out;
}

@keyframes toast-in {
  from { opacity: 0; transform: translateY(0.5rem); }
}

/* Компьютер: слева внизу, подальше от главных кнопок */
@media (min-width: 48rem) {
  .toasts { justify-items: start; }
}

@media (prefers-reduced-motion: reduce) {
  .toast { animation: none; }
}

7 правил уведомлений

  1. 01

    Громкость — по важности

    Счётчик, строка, тост, баннер, окно — от частого к редчайшему.

  2. 02

    Рядом с действием

    Если результат можно показать там, где кнопка, тост не нужен.

  3. 03

    «Вернуть» вместо вопроса

    Отмена после действия быстрее и надёжнее, чем «Вы уверены?» до него.

  4. 04

    Время, чтобы прочитать

    Около семи секунд для тоста с действием, пауза под курсором; ошибки не исчезают.

  5. 05

    Не закрывать кнопки

    Над нижней панелью на телефоне, в углу на компьютере.

  6. 06

    По одному

    Одинаковые сообщения сливаются в одно с итогом.

  7. 07

    Слышно экранной читалке

    role="status" для новостей, role="alert" для ошибок; фокус остаётся на месте.

Частые ошибки с уведомлениями

  1. Ошибка формы в тосте

    Сообщение исчезает, а человек остаётся искать, что было не так.

  2. Исчезает через две секунды

    Люди замечают, что что-то мелькнуло, но не что.

  3. Код вместо слов

    «Ошибка 500» не говорит ни что случилось, ни что делать.

  4. Тост поверх кнопки покупки

    На несколько секунд главное действие не нажать.

  5. Стопка одинаковых сообщений

    Пять тостов закрывают пол-экрана и говорят одно и то же.

  6. «Успешно!» на каждое действие

    Если результат виден на экране, сообщение только добавляет шума.

Вопросы об уведомлениях

Сколько тост должен висеть на экране?

Четыре-шесть секунд для короткого текста, около семи — с действием и сколько угодно, пока на нём курсор или фокус. Ошибки остаются, пока их не исправят.

Где показывать тосты?

Внизу на телефоне, над нижней панелью; на компьютере — в углу, подальше от главных кнопок, и в одном и том же месте на всех страницах.

Тост или сообщение рядом с кнопкой?

Рядом с кнопкой — когда действие и результат в одном месте: копирование, поле, фильтр. Тост — когда результат происходит в другом месте или в фоне.

Нужно ли вообще сообщать об успехе?

Когда его не видно само по себе: заявка отправлена, данные сохранены в фоне. Если изменение видно, сообщение не нужно.

Как экранная читалка узнаёт о тосте?

Через живую область: role="status" зачитывается, когда читалка освободится, role="alert" её перебивает — это только для ошибок.

Нужен ли сайту центр уведомлений?

В продукте с множеством событий — заказы, сообщения, комментарии — да: список со счётчиком. Обычному сайту он не нужен.

Форма

Интерфейс,
который отвечает

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

Или пишите на [email protected]