Анатомия модального окна: когда использовать диалог, drawer и bottom sheet - и как не сломать флоу пользователя

Анатомия модального окна: когда использовать диалог, drawer и bottom sheet - и как не сломать флоу пользователя

Коротко:

  • Три паттерна - диалог, drawer и bottom sheet - решают разные задачи. Путаница между ними ломает сценарий пользователя.
  • Диалог нужен для коротких подтверждений и критических решений. Он требует немедленного ответа.
  • Drawer подходит для дополнительного контента, фильтров и настроек, которые не прерывают основной экран полностью.
  • Bottom sheet - мобильный паттерн для быстрых действий и контекстных опций, доступных большим пальцем.
  • Главная ошибка - выбирать компонент по привычке, а не по характеру задачи.
  • Любой оверлей оправдан только тогда, когда пользователь должен сделать что-то прямо сейчас или получить контекст, не теряя место в интерфейсе.

Дизайнер открывает библиотеку компонентов и выбирает модалку - просто потому что она уже есть и разработчик её знает. Пользователь нажимает кнопку, экран тускнеет, появляется окно. Иногда это правильно. Чаще - нет.

Прерывающие оверлеи - один из самых переиспользуемых классов компонентов в интерфейсах. Их ставят везде: для подтверждений, для фильтров, для форм, для уведомлений, для настроек. В итоге пользователь постоянно выбивается из задачи, закрывает окна, которые не просил, и теряет контекст.

Эта статья про то, как выбирать между тремя конкретными паттернами - modal dialog, drawer и bottom sheet - и как проектировать каждый из них так, чтобы он помогал, а не мешал.

Что объединяет эти три паттерна

Все три компонента относятся к одному классу: они появляются поверх основного контента и требуют от пользователя какого-то действия или внимания. В терминологии UI их называют паттернами прерывания или оверлеями.

Ключевое слово здесь - прерывание. Когда человек работает с интерфейсом, у него есть задача и контекст. Оверлей разрывает этот контекст. Иногда это необходимо - например, когда нужно подтвердить необратимое действие. Иногда это лишнее - например, когда можно было просто показать панель справа.

Выбор паттерна - это не вопрос эстетики или привычки. Это вопрос о том, насколько сильно нужно прерывать пользователя и что он должен сделать дальше.

Modal dialog: когда нужен полный фокус

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

Именно поэтому его нужно использовать редко и точно.

Когда диалог оправдан

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

Когда диалог не нужен

  • Информация, которую можно показать inline или в тосте.
  • Форма с большим количеством полей - пользователь потеряет контекст.
  • Фильтры, настройки, дополнительный контент - для этого есть drawer.
  • Любые действия, которые не требуют немедленного решения.

Частая ошибка: диалог с одной кнопкой «Ок» - это не диалог, это уведомление. Если пользователю не из чего выбирать, оверлей не нужен. Используйте toast или inline-сообщение.

Анатомия хорошего диалога

Заголовок должен называть действие, а не задавать вопрос в стиле «Вы уверены?». Лучше: «Удалить проект?» или «Выйти без сохранения?». Тело - максимум два предложения с объяснением последствий. Кнопки - две: подтверждение и отмена. Деструктивное действие визуально отличается от нейтрального.

Размер окна фиксированный, не растягивается под контент. Если контент не помещается - это сигнал, что задача слишком сложная для диалога.

Drawer: когда контент нужен рядом, а не вместо

Drawer - это панель, которая выезжает сбоку (обычно справа) и накрывает часть экрана. В отличие от диалога, основной контент остаётся видимым за полупрозрачным оверлеем. Пользователь понимает, где находится, и может вернуться к задаче одним закрытием.

Это делает drawer подходящим для всего, что дополняет текущий контекст, а не заменяет его.

Когда drawer работает хорошо

  • Фильтры и сортировка в списках и таблицах - пользователь видит результат сразу после закрытия.
  • Детали объекта: карточка клиента, описание задачи, параметры товара.
  • Настройки раздела, которые не требуют отдельной страницы.
  • Многошаговые формы средней сложности, где контекст страницы важен.
  • Навигационное меню на мобайле (hamburger-меню).

Типичные проблемы с drawer

Первая - слишком узкая панель для сложного контента. Если внутри drawer нужна прокрутка и вложенные элементы, скорее всего, это задача для отдельной страницы.

Вторая - drawer поверх drawer. Вложенные панели путают пользователя и ломают навигацию. Если нужен второй уровень, лучше переключать контент внутри одной панели.

Третья - использование drawer на мобайле вместо bottom sheet. На телефоне боковая панель неудобна: до неё сложно дотянуться, она перекрывает контент неестественно. Для мобайла есть более подходящий паттерн.

Пример: в таблице с заказами пользователь кликает на строку - справа выезжает drawer с деталями заказа. Он видит список заказов за панелью, понимает контекст и может сразу перейти к следующему. Если бы открывался диалог, контекст был бы потерян.

Bottom sheet: мобильный паттерн для быстрых действий

Bottom sheet - панель, которая появляется снизу экрана. Это нативный паттерн для мобайла: он удобен большим пальцем, соответствует ожиданиям пользователей iOS и Android, и хорошо работает для коротких задач.

Существует два варианта. Modal bottom sheet блокирует основной контент - ведёт себя как диалог, только снизу. Persistent bottom sheet остаётся на экране постоянно и не блокирует взаимодействие с контентом выше.

Когда нужен bottom sheet

  • Контекстное меню действий: поделиться, скопировать, удалить, переименовать.
  • Быстрый выбор из небольшого списка: выбрать способ оплаты, выбрать адрес доставки.
  • Подтверждение действия на мобайле - вместо диалога, который на маленьком экране выглядит громоздко.
  • Фильтры и сортировка в мобильном приложении.
  • Краткая информация о точке на карте, объекте в списке.

Ограничения паттерна

Bottom sheet плохо работает на десктопе - там он выглядит чужеродно и нарушает пространственную логику интерфейса. Не стоит переносить его на большие экраны ради «единообразия».

Ещё одна ловушка - перегрузка контентом. Если панель занимает больше 70% экрана и требует прокрутки, это уже не быстрое действие. Такой сценарий лучше решать через отдельный экран или полноэкранный оверлей.

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

Сравнение трёх паттернов

КритерийModal dialogDrawerBottom sheet
Блокирует интерфейсПолностьюЧастичноЧастично (modal) / нет (persistent)
ПлатформаЛюбаяДесктоп, планшетМобайл
Подходящий контентПодтверждения, короткие формыДетали, фильтры, настройкиДействия, быстрый выбор
Размер контентаНебольшой, фиксированныйСредний, с прокруткойНебольшой или средний
ЗакрытиеКнопка / EscapeКнопка / клик вне / EscapeСвайп вниз / кнопка / тап вне

Как выбрать паттерн: три вопроса

Перед тем как открыть библиотеку компонентов, ответьте на три вопроса.

Насколько срочно пользователь должен отреагировать? Если действие нельзя отложить и оно влияет на данные - нужен диалог. Если пользователь может закрыть панель и вернуться позже - подойдёт drawer или bottom sheet.

Нужен ли пользователю контекст основного экрана? Если да - диалог не подходит, он скрывает всё за собой. Drawer оставляет контекст видимым. Bottom sheet тоже, если он не занимает весь экран.

На каком устройстве происходит сценарий? На мобайле drawer неудобен - используйте bottom sheet. На десктопе bottom sheet выглядит странно - используйте drawer или диалог.

Простое правило: если задача требует немедленного решения - диалог. Если нужен дополнительный контент без потери места - drawer. Если это мобайл и действие быстрое - bottom sheet.

Общие ошибки при проектировании оверлеев

Слишком много информации внутри

Оверлей - это не страница. Если внутри нужна навигация, вкладки, длинные формы и вложенные списки, это сигнал, что задача требует отдельного экрана. Перегруженный оверлей сложно использовать и сложно поддерживать.

Нет явного способа закрыть

Пользователь всегда должен понимать, как выйти. Для диалога - кнопка «Отмена» или крестик. Для drawer - крестик и клик по затемнённой области. Для bottom sheet - свайп вниз и тап вне панели. Если хотя бы один способ отсутствует, часть пользователей застрянет.

Оверлей открывается без действия пользователя

Автоматически открывающийся диалог или панель - почти всегда плохая идея. Исключение: критическая системная ошибка. В остальных случаях пользователь должен сам инициировать появление оверлея.

Один и тот же паттерн для разных задач

Если в продукте все задачи решаются через диалог - это не система, это привычка. Разные задачи требуют разных решений. Подтверждение удаления и просмотр деталей объекта - принципиально разные сценарии.

Игнорирование доступности

Оверлеи требуют особого внимания к фокусу. При открытии фокус должен переходить внутрь компонента. При закрытии - возвращаться к элементу, который его вызвал. Без этого пользователи с клавиатурной навигацией теряются в интерфейсе. Подробнее об этом - в ARIA Authoring Practices Guide для диалогов.

Детали, которые влияют на качество

Анимация появления

Диалог появляется по центру - достаточно лёгкого fade или небольшого scale. Drawer выезжает сбоку - slide. Bottom sheet появляется снизу - slide up. Анимация должна подчёркивать направление движения, а не быть самоцелью. 200-300 мс - достаточно для большинства случаев.

Затемнение фона

Overlay за оверлеем помогает пользователю понять, что основной контент временно недоступен. Стандартное значение - чёрный с прозрачностью 40-60%. Слишком тёмный фон тревожит, слишком светлый не создаёт нужного разделения.

Прокрутка внутри

Если контент внутри оверлея прокручивается, основная страница не должна прокручиваться одновременно. Это стандартная проблема на мобайле, которую часто упускают при проектировании.

Заголовок и кнопки действий

В drawer и bottom sheet заголовок помогает пользователю понять, что открылось. Кнопки действий лучше размещать внизу панели - это соответствует ожиданиям и удобно для большого пальца на мобайле.

Чеклист перед финальным решением

  1. Определён ли тип задачи: подтверждение, детали, действие, форма?
  2. Известно ли устройство, на котором происходит сценарий?
  3. Нужен ли пользователю контекст основного экрана во время взаимодействия?
  4. Требует ли задача немедленного ответа или можно отложить?
  5. Есть ли явный способ закрыть оверлей?
  6. Фокус переходит внутрь при открытии и возвращается при закрытии?
  7. Контент помещается без вложенных уровней навигации?
  8. Анимация соответствует направлению появления компонента?
  9. Основная страница не прокручивается, пока открыт оверлей?
  10. Деструктивные действия визуально отличаются от нейтральных?

Когда оверлей вообще не нужен

Прежде чем выбирать между тремя паттернами, стоит задать более простой вопрос: а нужен ли оверлей вообще? Многие задачи, которые по привычке решают через всплывающие панели, на самом деле решаются проще.

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

Toast-уведомление заменяет диалог там, где пользователю просто нужно сообщить об успехе или ошибке. Если нет выбора и нет последствий, прерывать флоу не нужно.

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

Раскрывающийся блок (accordion или expandable section) решает задачу показа дополнительных деталей прямо на странице, без наложения слоёв.

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

Вложенные оверлеи: почему это почти всегда ошибка

Вложенный оверлей - это ситуация, когда поверх уже открытого компонента появляется ещё один. Диалог внутри drawer, bottom sheet поверх другого bottom sheet, подтверждение внутри формы в панели.

Технически это реализуемо. Практически - почти всегда плохое решение.

Пользователь теряет ориентацию: непонятно, сколько слоёв открыто и в каком порядке их закрывать. Управление фокусом становится непредсказуемым. Анимации накладываются и создают визуальный шум. На мобайле вложенные панели занимают весь экран и ведут себя непоследовательно.

Если логика сценария требует второго оверлея, это сигнал пересмотреть архитектуру. Чаще всего помогает одно из трёх решений: переключать контент внутри одной панели (например, показывать разные шаги в одном drawer), разбить задачу на отдельные экраны, или упростить сценарий так, чтобы второй уровень не понадобился.

Единственное исключение - системный диалог подтверждения поверх пользовательского оверлея. Например, пользователь заполнял форму в drawer и случайно нажал закрыть. Диалог «Вы уверены, что хотите выйти? Данные не сохранятся» оправдан, потому что он защищает от потери данных и появляется один раз.

Адаптация паттернов между платформами

Один из частых вопросов при проектировании кросс-платформенных продуктов: как адаптировать оверлеи между мобайлом и десктопом, если кодовая база общая?

Прямой перенос почти никогда не работает. Bottom sheet на десктопе выглядит чужеродно и нарушает пространственную логику. Drawer на мобайле неудобен для большого пальца. Диалог на маленьком экране может занимать почти всё пространство и выглядеть как отдельная страница.

Практичный подход - проектировать поведение, а не компонент. Одна и та же задача на мобайле решается через bottom sheet, на десктопе через drawer или диалог. Это не непоследовательность, это адаптация под контекст устройства.

ЗадачаМобайлПланшетДесктоп
Подтверждение действияBottom sheet или диалогДиалогДиалог
Фильтры и сортировкаBottom sheetDrawer или bottom sheetDrawer
Детали объектаОтдельный экран или bottom sheetDrawerDrawer
Контекстное меню действийBottom sheetBottom sheet или popoverPopover или контекстное меню
Основная навигацияDrawer (hamburger)Drawer или боковая панельБоковая панель

Планшет занимает промежуточную позицию и требует отдельного решения для каждого сценария. Ориентируйтесь на то, как пользователь держит устройство: в портретной ориентации поведение ближе к мобайлу, в альбомной - к десктопу.

Хорошая практика: при проектировании кросс-платформенного продукта сначала определите поведение для каждого устройства отдельно, а потом ищите общий компонент в коде. Не наоборот. Компонент должен подстраиваться под задачу, а не задача под компонент.

FAQ

Чем modal dialog отличается от обычного popup?

Диалог - это структурированный компонент с заголовком, телом и кнопками действий. Он блокирует интерфейс и требует явного ответа. Popup - более широкое понятие, которое включает и тосты, и тултипы, и рекламные оверлеи. В профессиональном контексте лучше использовать точные термины.

Можно ли использовать drawer на мобайле?

Технически можно, но это неудобно. Боковая панель на телефоне требует горизонтального жеста, который конкурирует с системной навигацией. Для мобайла bottom sheet - более естественный выбор. Drawer на мобайле оправдан только для основной навигации (hamburger-меню).

Когда использовать модалку вместо отдельной страницы?

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

Как правильно называть кнопки в диалоге подтверждения?

Кнопки должны называть действие, а не говорить «Да» и «Нет». Например: «Удалить» и «Отмена», «Выйти» и «Остаться», «Отправить» и «Вернуться к редактированию». Это снижает когнитивную нагрузку и уменьшает риск случайного деструктивного действия.

Что такое persistent bottom sheet и когда его использовать?

Это панель, которая остаётся на экране постоянно и не блокирует взаимодействие с контентом выше. Классический пример - мини-плеер в Spotify или панель с деталями маршрута в картах. Подходит для контента, который нужен постоянно, но не должен занимать весь экран.

Нужен ли крестик в диалоге?

Зависит от контекста. Если диалог требует явного выбора (например, подтверждение удаления), крестик может быть лишним - пользователь должен нажать «Отмена». Если диалог информационный или форма необязательная - крестик нужен. Главное: всегда должна быть кнопка «Отмена» или её эквивалент.

Как обеспечить доступность оверлея?

При открытии фокус переходит на первый интерактивный элемент внутри. Фокус не выходит за пределы оверлея, пока он открыт (focus trap). При закрытии фокус возвращается к элементу, который вызвал открытие. Escape закрывает оверлей. Это базовые требования по WCAG и ARIA.

Итог

Выбор между диалогом, drawer и bottom sheet - это не вопрос вкуса или доступных компонентов. Это решение о том, насколько сильно нужно прерывать пользователя и что он должен сделать в этот момент. Диалог требует немедленного ответа и полного фокуса. Drawer добавляет контент, не скрывая основной экран. Bottom sheet решает быстрые задачи на мобайле удобным жестом.

Большинство проблем с оверлеями возникает не из-за неправильной реализации, а из-за неправильного выбора паттерна на этапе проектирования. Если задать себе три вопроса - срочность, контекст, устройство - правильный компонент обычно становится очевидным.

Хорошо спроектированный оверлей незаметен: пользователь делает нужное действие и возвращается к задаче без ощущения, что его прервали.