Модальное окно для мобильных устройств

Обновлено: 27.04.2024

Используйте плагин модального окна Bootstrap для JavaScript, чтобы добавить на свой сайт диалоговые окна для лайтбоксов, уведомлений пользователей или полностью настраиваемого контента.

Как это устроено

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

  • Модальные окна создаются с помощью HTML, CSS и JavaScript. Они располагаются поверх всего остального в документе и удаляют прокрутку из , так что вместо этого прокручивается модальное содержимое.
  • Клик по модальному «фону» автоматически закрывает модальный.
  • Bootstrap поддерживает только одно модальное окно за раз. Вложенные модальные окна не поддерживаются, поскольку мы считаем, что они неудобны для пользователей.
  • В модальных окнах используется position: fixed , что иногда может быть немного специфичным при его рендеринге. По возможности размещайте модальный HTML-код на верхнем уровне, чтобы избежать потенциального вмешательства со стороны других элементов. Вы, вероятно, столкнетесь с проблемами при вложении .modal в другой фиксированный элемент.
  • Еще раз, из-за position: fixed есть некоторые предостережения при использовании модальных окон на мобильных устройствах. См. нашу документацию по поддержке браузеров для получения дополнительной информации.
  • Из-за того, как HTML5 определяет свою семантику, атрибут HTML autofocus не действует в Bootstrap. модальные окна. Чтобы добиться того же эффекта, используйте собственный JavaScript:

Эффект анимации этого компонента зависит от медиазапроса prefers-reduced-motion . См. раздел с уменьшенным движением в нашей документации по специальным возможностям.

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

Примеры

Модальные компоненты

Ниже приведен пример статического модального окна (это означает, что его position и display были переопределены). Включены модальный заголовок, модальное тело (требуется для padding ) и модальный нижний колонтитул (необязательно). Мы просим вас по возможности включать модальные заголовки с действиями по отклонению или предоставить другое явное действие по отклонению.

Заголовок модального окна

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

Живая демонстрация

Переключите рабочую модальную демонстрацию, нажав кнопку ниже. Он будет скользить вниз и исчезать из верхней части страницы.

Заголовок модального окна

Уууу, вы читаете этот текст в модальном!

Статический фон

Заголовок модального окна

Я не закроюсь, если ты щелкнешь вне меня. Даже не пытайтесь нажимать клавишу выхода.

Прокрутка длинного контента

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

Заголовок модального окна

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

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

Заголовок модального окна

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

Это содержимое должно появиться внизу после прокрутки.

Центрование по вертикали

Добавьте .modal-dialog-centered к .modal-dialog для вертикального центрирования модального окна.

Заголовок модального окна

This is a vertically centered modal.

Заголовок модального окна

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

Всплывающие подсказки и всплывающие окна

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

Заголовок модального окна
Всплывающие окна в модальном окне

Эта кнопка вызывает всплывающее окно при нажатии.

Всплывающие подсказки в модальном окне

Эта ссылка и эта ссылка имеют всплывающие подсказки при наведении курсора.

Использование сетки

Используйте сеточную систему Bootstrap в модальном окне, вложив .container-fluid в .modal-body . Затем используйте обычные классы системы сетки, как и везде.

Сетки в модальных окнах

Изменяющееся модальное содержимое

У Вас есть несколько кнопок, которые запускают одно и то же модальное окно с немного разным содержимым? Используйте event.relatedTarget и HTML data-* атрибуты, чтобы изменять содержимое модального окна в зависимости от какая кнопка была нажата.

Ниже представлена живая демонстрация, за которой следуют примеры HTML и JavaScript. Для получения дополнительной информации прочтите документацию по модальным событиям для получения подробной информации о relatedTarget .

Открыть модальное окно для @mdo Открыть модальное окно для @fat Открыть модальное окно для @getbootstrap

Переключение между модальными окнами

Модалка 1
Модалка 2

Изменение анимации

Переменная $modal-fade-transform определяет состояние преобразования .modal-dialog перед модальной плавной анимацией, переменная $modal-show-transform определяет преобразование .modal-dialog в конец модальной плавной анимации.

Если Вам нужна, например, анимация с увеличением, Вы можете установить $modal-fade-transform: scale(.8) .

Удаление анимации

Для модальных окон, которые просто появляются, а не исчезают при просмотре, удалите класс .fade из Вашей модальной разметки.

Динамические высоты

Если высота модального окна изменяется, пока он открыт, Вы должны вызвать myModal.handleUpdate() , чтобы скорректировать положение модального окна в случае появления полосы прокрутки.

Доступность

Не забудьте добавить aria-labelledby=". " , ссылаясь на Заголовок модального окна, в .modal . Кроме того, Вы можете дать описание Вашего модального диалога с помощью aria-describedby в .modal . Обратите внимание, что Вам не нужно добавлять role="dialog" , поскольку мы уже добавляем его через JavaScript..

Встраивание видео с YouTube

Встраивание видео YouTube в модальные окна требует дополнительного JavaScript не в Bootstrap для автоматической остановки воспроизведения и т.д. См. этот полезный пост о переполнении стека для получения дополнительной информации.

Дополнительные размеры

Модальные окна имеют три необязательных размера, доступных через классы модификаторов, которые помещаются в .modal-dialog . Эти размеры действуют в определенных контрольных точках, чтобы избежать горизонтальных полос прокрутки на более узких окнах просмотра.

Размер Класс Максимальная ширина модального окна
Маленькое .modal-sm 300px
По умочланию нет 500px
Большое .modal-lg 800px
Очень большое .modal-xl 1140px

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

Очень большое модальное окно
Большое модальное окно
Маленькое модальное окно

Полноэкранное модальное окно

Другое переопределение - это возможность вывести модальное окно, охватывающее область просмотра пользователя, доступное через классы модификаторов, которые помещаются в .modal-dialog .

Класс Доступность
.modal-fullscreen Всегда
.modal-fullscreen-sm-down Меньше 576px
.modal-fullscreen-md-down Меньше 768px
.modal-fullscreen-lg-down Меньше 992px
.modal-fullscreen-xl-down Меньше 1200px
.modal-fullscreen-xxl-down Меньше 1400px

Полноэкранный Полноэкранный меньше sm Полноэкранный меньше md Полноэкранный меньше lg Полноэкранный меньше xl Полноэкранный меньше xxl

Полноэкранное модальное окно
Полноэкранный меньше sm
Полноэкранный меньше md
Полноэкранный меньше lg
Полноэкранный меньше xl
Полноэкранный меньше xxl

Переменные

Адаптивные полноэкранные модальные окна генерируются с помощью карты $breakpoints и цикла в scss/_modal.scss .

Использование

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

Через атрибуты данных

Переключение

Отклонение

Отклонение может быть достигнуто с помощью атрибута data на кнопке внутри modal, как показано ниже:

или на кнопке за пределами modal с помощью data-bs-target , как показано ниже:

Хотя поддерживаются оба способа отклонения модального окна, имейте в виду, что удаление модального окна извне не соответствует шаблону проектирования модального диалога WAI-ARIA. Делайте это на свой страх и риск.

Через JavaScript

Создайте модальное окно с одной строкой JavaScript:

Параметры

Параметры могут передаваться через атрибуты данных или JavaScript. Для атрибутов данных добавьте имя параметра к data-bs- , как в data-bs-backdrop="" .

Наименование Тип По умолчанию Описание
backdrop boolean or the string 'static' true Включает элемент модального фона. В качестве альтернативы укажите static для фона, который не закрывает модальное окно при нажатии.
keyboard boolean true Закрывает модальное окно при нажатии клавиши выхода.
focus boolean true При инициализации фокусируется на модальном окне.

Методы

Асинхронные методы и переходы

Все методы API асинхронны и запускают переход. Они возвращаются к вызывающей стороне, как только переход начинается, но до его завершения. Кроме того, вызов метода переходного компонента будет проигнорирован.

Passing options

Активирует Ваш контент как модальное окно. Принимает необязательные параметры object .

toggle

Вручную переключает модальное окно. Возврат к вызывающей стороне до того, как модальное окно было фактически показано или скрыто (т.е. до того, как произойдет событие shown.bs.modal или hidden.bs.modal ).

Открывает модальное окно вручную. Возврат к вызывающей стороне до фактического отображения модального окна (т.е. до того, как произойдет событие shown.bs.modal ).

Also, you can pass a DOM element as an argument that can be received in the modal events (as the relatedTarget property).

Скрывает модальное окно вручную. Возврат к вызывающей стороне до того, как модальное окно было фактически скрыто (т.е. до того, как произойдет событие hidden.bs.modal ).

handleUpdate

Вручную скорректируйте положение модального окна, если высота модального окна изменяется, пока он открыт (то есть в случае появления полосы прокрутки).

dispose

Уничтожает элемент модальное окно. (Удаляет сохраненные данные в элементе DOM)

getInstance

Статический метод, позволяющий получить модальный экземпляр, связанный с элементом DOM.

getOrCreateInstance

Статический метод, который позволяет вам получить модальный экземпляр, связанный с элементом DOM, или создать новый, если он не был инициализирован.

События

Модальный класс Bootstrap предоставляет несколько событий для подключения к модальным функциям. Все модальные события запускаются в самом модальном окне (то есть в ).


Что такое мобильные модальные окна?

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

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

Существует 3 типа мобильных модальных окон.

1. Попапы

Хорошая новость в том, что этот элемент пользовательского интерфейса может и не использоваться. Вместо того, чтобы полагаться на стандартное всплывающее окно на сером фоне, вы можете использовать фирменный оверлей (окно, закрывающее часть экрана) или полноэкранный модальный режим при запросе разрешений. Например, Babbel предлагает пользователям сначала предоставить разрешения для устройств с помощью своего собственного фирменного запроса. Только если пользователи ответят положительно и захотят предоставить доступ к микрофону, им покажут стандартное всплывающее окно iOS — в этот момент у них уже будет достаточно контекста для подтверждения запроса.

Мобильные модальные окна

2. Частичный оверлей

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

Так как оверлеи занимают только часть экрана, они ощущаются несколько менее агрессивными по сравнению с полноэкранные модальные окнами (хотя функционально они одинаковы).

Мобильные модальные окна

3. Полноэкранные модальные окна

Мобильные модальные окна

Итак, как сделать хорошее мобильное модальное окно?

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

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

Вот несколько советов, которые владельцы мобильных приложений могут использовать, чтобы максимально задействовать свое уменьшенное творческое пространство:

Фирменный, индивидуальный дизайн, который подходит вашему приложению

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

Сильный текст и убедительный CTA‍

Тайминг и таргетинг

Интересный визуальные вид

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

8 лучших примеров мобильных модальных окон

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

1. Новый вид Gmail

Мобильные модальные окна

Мобильные модальные окна

2. Включение push-уведомлений в Youtube TV

Мобильные модальные окна

3. Функции умного дома Spotify

Мобильные модальные окна

Spotify знает, что возможность потоковой передачи их приложения на несколько устройств означает лучшее удержание и доход. Их простое модальное решение отлично справляется с задачей возврата пользователей.

4. Простое обновление дизайна Sephora

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

Мобильные модальные окна: 8 лучших примеров использования

5. Привлекательные допродажи Venmo

Дополнительные продажи являются важной, но сложной частью эффективной маркетинговой стратегии приложения. Venmo использует привлекательный мобильный модал, чтобы пользователи знали (и подписывались) на уникальную карту компании.

Мобильные модальные окна: 8 лучших примеров использования

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

6. Индивидуальное предложение Caviar

Мобильные модальные окна: 8 лучших примеров использования

Продвижение в приложении хорошо работает для 2 разных аудиторий:

  • Латентные пользователи Caviar, которым нужен последний толчок для размещения заказа
  • Постоянные пользователи Caviar, которые заслуживают награды за свою лояльность

7. Игровые достижения Nike Run Club

Мобильные модальные окна: 8 лучших примеров использования

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

8. Запрос на отзыв в OpenTable

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

Мобильные модальные окна: 8 лучших примеров использования

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

Мобильные модальные окна — возможность улучшить вовлечение и удержание

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


Модальные окна на мобильных устройствах: оптимальное решение


Аудио перевод статьи

Модальные окна — стандартный элемент интерфейса.

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

Но если на больших экранах такое решение довольно эффективно, на мобильных устройствах использование модальных окон ограничено. В статье вы найдете один из вариантов реализации подобных элементов. Дайте шанс этому подходу, когда будете проектировать свое следующее приложение!

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

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


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


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

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

Всплывающие модальные окна

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

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


Хедер — это верхняя часть всплывающего модального окна. Он включает заголовок, кнопку “Закрыть” и специальный ползунок. Последний расположен по центру сверху — пользователи могут потянуть за него, чтобы смахнуть окно с экрана, вместо того, чтобы нажимать на крестик. Такое взаимодействие предоставляет им больше возможностей для перемещения между экранами.

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

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

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

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




Начнем это исследование со следующего смелого утверждения:

Существует два типа экранов:

  1. Модальные экраны
  2. Немодальные экраны

Что такое «модальный экран»?

Модальные экраны можно обнаружить в различных его формах и представлениях, например одним из ниже перечисленных в списке:

  • Полноэкранные модальные виды
  • Всплывающие окна
  • Поп-апы
  • Лайтбоксы

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

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

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



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

Основное различие заключается в способе взаимодействия с каждым из окон. В то время как немодальный экран позволяет пользователям вернуться к родительскому экрану, модальный экран требует, чтобы пользователи завершили определённое действие, прежде чем вернуться в главное окно (такое как нажатие кнопки «Сохранить» в нашем примере) или отменить текущее действие, вызвавшее модальное окно.

Наиболее ярким визуальным индикатором для немодальных окон является навигация (панель вкладок в нашем примере). Немодальные экраны позволяют пользователям переходить назад и вперед на основном уровне навигации приложения.

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

Почему следует использовать модальность?


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

«Модальность создает фокусировку, не давая людям заниматься другими делами, прежде чем они не завершат задачу или не отклонят вызванное в модальном окне представление» — Apple

Когда следует использовать модальность?

Теперь, когда мы знаем, как выглядит модальный экран. Как же сравнить его с немодальным экраном и какова его цель? Прежде всего мы должны спросить себя: «В какой ситуации мы должны его использовать?»

Давайте представим, что мы создаем «гениальный и инновационный» стартап под названием «Purrrfect». Это база данных котят, которая позволяет пользователям загружать, просматривать и комментировать GIF-изображения милых котяток.

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



Пользовательский поток приложения «Purrrfect»

Кроме того, пользователь может выполнять дополнительные действия на каждом из этапов. Например, он может добавить другого котёнка в базу данных на экране списка котят. Или он может редактировать данные на экране подробностей котенка.

А теперь надо понять, какой из этих экранов является модальным, а какой нет? Классификация в данном случае вызывает сложность, но вот моё личное эмпирическое правило:

«Автономный процесс» — это конкретное действие, которое имеет четкую начальную и конечную точку в процессе.

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

Google формулирует это правило следующим образом:

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

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


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

Давайте вернемся к нашему приложению. Возможный интерфейс для «Purrrfect» может выглядеть так:



Пользовательский интерфейс «Purrrfect»

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

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

Минимизируйте использование модальности. Как правило, люди предпочитают взаимодействовать с приложениями нелинейными способами. Рассматривайте возможность создания модального контекста только в тех случаях, когда важно привлечь чье-либо внимание, когда задача должна быть завершена или прекращена, чтобы продолжить использование приложения или сохранить важные данные. — Apple

Конечно, интерфейс может прекрасно работать без строгого различия между модальным и немодальным представлениями. Тем не менее, концепция модальности глубоко заложена в интерфейсных экосистемах Apple, Google, Microsoft и других компаний, которые разработали соответствующие ожидания для своих постоянных пользователей.

Как следует использовать модальность?

К настоящему времени надеюсь что возникло общее понимание того, когда использовать модальность. Остается только один вопрос: «Как мы спроектируем модальность?». Вот быстрый чеклист для использования модальных экранов:

  • Всегда показывайте кнопку закрытия/скрытия модального окна (или «отмена», «отменить», «свернуть») в верхней панели навигации. Когда пользователь теряется, он может легко закрыть такое окно и вернуться на уровень приложения, откуда было вызвано модальное окно.
  • Кнопки отмены на iOS и Android чаще всего располагаются в верхней левой части панели навигации. Android предпочитает иконку закрытия «X», в то время как iOS предпочитает кнопку с надписью «Отмена». Тем не менее, кнопки иконок также довольно распространен и в iOS.
  • Кнопки подтверждения действия на модальном окне в iOS и Android по умолчанию расположены в верхней правой части панели навигации. Тем не менее, это размещение может быть недоступным для пользователя на устройствах с большой диагональю. Поэтому фиксированное плавающее размещение такого в нижней части экрана или в конце страницы может быть неплохим альтернативным решением.

Многоступенчатые модальные окна

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

При размещении основного действия («сохранить», «применить» или «продолжить») в нижней части экрана (как было рекомендовано ранее) в верхней правой области второго шага модального блока всегда освобождается место для дополнительной кнопки отмены. Хотя перемещение выглядит более логичным слева направо, это размещение все же лучше для модального окна, чем отсутствие возможности закрывать модальный экран на дочерних (предшествующих) экранах.


Заключение


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

Вёрстка таких окон сначала кажется простой задачей. Модальные окна можно сделать даже без помощи JS только лишь с помощью CSS, но на практике они оказываются неудобными, и из-за маленьких недочетов модальные окна раздражают посетителей сайта.

В итоге было задумано сделать собственное простое решение.


Вообще говоря, есть несколько готовых скриптов, JavaScript библиотек, реализующих функционал модальных окон, например:

  • Arctic Modal,
  • jquery-modal,
  • iziModal,
  • Micromodal.js,
  • tingle.js,
  • Bootstrap Modal (из библиотеки Bootstrap) и др.

(в статье не рассматриваем решения на базе Frontend-фреймворков)

Несколькими из них я пользовался сам, но почти у всех находил какие-то недостатки. Некоторые из них требуют подключения библиотеки jQuery, которая есть не на всех проектах. Для разработки своего решения, нужно сначала определиться с требованиями.

Что мы ждём от модальных окон? Отвечая на этот вопрос, я основывался на докладе «Знакомьтесь, модальное окно» Анны Селезнёвой, а так-же на относительно старой статье NikoX «arcticModal — jQuery-плагин для модальных окон».

Итак, чтобы нам хотелось видеть?

Дисклеймер: Прежде чем мы рассмотрим подробности, сразу дам ссылку на готовый код получившейся библиотеки (HystModal) на GitHub, а также ссылку на демо+документацию.

Начнём с разметки.

1. Разметка HTML и CSS

1.1. Каркас модальных окон

Как открыть окно быстро? Самое простое решение: разместить всю разметку модального окна сразу в HTML странице. Затем скрывать/показывать это окно при помощи переключения классов CSS.

Набросаем такую разметку HTML (я назвал этот скрипт «hystmodal»):

Сделаем так, чтобы .hystmodal растягивался на всё окно браузера и закрывал собой содержимое страницы. Чтобы этого добиться, установим фиксированное позиционирование в CSS и приравняем свойства top, bottom, left и right к нулю.

В этом коде сделаны ещё две вещи:

  1. Так как мы хотим центрировать окно внутри страницы, превращаем .hystmodal в flex-контейнер с выравниваем его потомков по центру по вертикали и горизонтали.
  2. Окно может быть больше высоты экрана браузера, поэтому мы устанавливаем overflow-y: auto , чтобы при переполнении возникала полоса прокрутки. Также, для сенсорных экранов (в основном для Safari) нам стоит установить свойство -webkit-overflow-scrolling: touch , чтобы сенсорная прокрутка работала именно на этом блоке а не на странице.

Теперь установим стили для самого окна.

Кажется возникли сложности.

Проблема №1. Если высота окна больше высоты окна браузера, то контент окна будет обрезан сверху.


Это возникает из-за свойства justify-content: center . Оно позволяет нам удобно выровнять потомков по основной оси (по вертикали), но если потомок становится больше родителя то часть его становится недоступной даже при прокручиваемом контейнере. Подробнее можно посмотреть на stackoverflow. Решение – установить justify-content: flex-start , а потомку установить margin:auto . Это выровняет его по центру.

Проблема №2. В ie-11 если высота окна больше высоты окна браузера, то фон окна обрезается.

Решение: мы можем установить flex-shrink:0 потомку – тогда обрезки не происходит.

Проблема №3. В браузерах кроме Chrome нет отступа от нижней границы окна (т.е. padding-bottom не сработал).

Сложно сказать баг это браузеров или наоборот соответствует спецификации, но решения два:

  • установить псевдоэлемент ::after после потомка и дать ему высоту вместо padding
  • обернуть элемент в дополнительный блок и дать отступы уже ему.

Воспользуемся вторым методом. Добавим обертку .hystmodal__wrap . Так мы заодно обойдём и проблему №1, а вместо padding у родителя установим margin-top и margin-top у самого .hystmodal__window .

Наш итоговый html:

В код также добавлены некоторые aria и role атрибуты для обеспечения доступности.

Обновленный код CSS для обертки и окна.

1.2 Скрываем окно

Сейчас наше окно всегда видно. Когда говорят о скрытии элементов, первое что приходит на ум это переключать свойство display со значения none до нашего значения flex.

Но этот подход нас не устроит, ведь свойство display не анимируется. Все переходы дочерних элементов, указанные в свойстве transition, работать не будут.

Нам поможет другое свойство visibility:hidden . Оно скроет окно визуально, хотя и зарезервирует под него место. А так как все будущие окна на странице имеют фиксированное
позиционирование – они будут полностью скрыты и не повлияют на остальную страницу. Кроме того, на элементы с visibility:hidden нельзя установить фокус с клавиатуры, а от скрин-ридеров мы уже скрыли окна с помощью атрибута aria-hidden="true" .

Добавим также классы для открытого окна:

1.3 Оформление подложки

В лучшем случае, нам нужен отдельный html-элемент в качестве оверлея. Можно использовать и имеющийся элемент модального окна .hystmodal в качестве оверлея, но тогда анимация на этом элементе (например переход opacity) будет затрагивать и внутренние элементы. В итоге, не получится анимировать разные свойства для окна и оверлея отдельно.

Просто разместим элемент .hystmodal__shadow прямо перед закрывающим . В будущем, сделаем так, чтобы этот элемент создавался автоматически из js при инициализации библиотеки.

1.4 Отключение прокрутки страницы

Когда модальное окна открывается, мы хотим, чтобы страница под ним не прокручивалась.
Самый простой способ этого добиться — повесить overflow:hidden для body или html, когда окно открывается. Однако с этим есть проблема:

Проблема №4. В браузере Safari на iOS страница будет прокручиваться, даже если на тег html или body повешен overflow:hidden .
Решается двумя способами, либо блокированием событий прокрутки (touchmove, touchend или touchsart) из js вида:

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

ps: можно конечно применить библиотеку scroll-lock, в которую заложено это решение, но в статье было решено воспользоваться другим вариантом.

Другое решение – основано частично на CSS. Пусть когда окно открывается, на элемент будет добавляться класс .hystmodal__opened :

Благодаря position:fixed , окно не будет прокручиваться даже в safari, однако здесь тоже не всё гладко:

Проблема №5. При открытии/закрытии окна страница прокручивается в начало.
Действительно, это происходит из-за изменения свойства position, текущая прокрутка окна сбрасывается.

Для решения, нам нужно написать следующий JS (упрощенно):

При открытии:

При закрытии:

Отлично, приступим к JavaScript коду.

2. Код JavaScript

2.2 Каркас библиотеки

Нам нужна совместимость со старыми браузерами включая IE11 поэтому нам нужно выбрать из 2 вариантов кодинга:

  • Разрабатывать на старом стандарте ES5, и использовать только те фичи, которые поддерживают все браузеры.
  • Применить современный синтаксис ES6, но подключить транспайлер Babel, который автоматически преобразует код для всех браузеров и встроит необходимые полифилы.
    Было принято решение использовать второй вариант, с прицелом на будущее.
    Приступим.

Основа нашей библиотеки единственный класс HystModal . Ниже я приведу скелет кода с комментариями, а потом добавим остальной функционал.

Итак, мы описали класс HystModal . Чтобы всё работало, нужно всего лишь подключить наш скрипт и создать экземпляр класса:

Проблема №6: если в браузере есть фиксированный скроллбар (который влияет на ширину страницы), то при открытии/закрытии окна происходит сдвиг контента, когда полоса прокрутки то появляется то пропадает.

Действительно – скроллбар пропадает и контент страницы перераспределяется. Чтобы решить эту проблему, можно добавить отступ справа к тегу html, равный ширине скроллбара когда он пропадает.

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

Дополним метод _bodyScrollControl()

Почему код метода close() упрощён? Дело в том, что просто убирая классы CSS у элементов, мы не можем анимировать закрытие окна.

Проблема №7. При закрытии окна, свойство visibility:hidden применяется сразу и не даёт возможности анимировать закрытие окна.

Причина этого известна: свойство visibility:hidden не анимируется. Конечно, можно обойтись без анимации, но, если она нужна, сделаем следующее.

  • Создадим дополнительный CSS-класс .hystmodal—moved почти такой-же как и .hystmodal--active
  • Затем при закрытии сначала добавим этот класс к окну и повесим обработчик события «transitionend» на модальном окне. Затем удалим класс `.hystmodal—active , таким образом вызывая css-переход. Как только переход завершится, сработает обработчик события «transitionend», в котором сделаем всё остальное и удалим сам обработчик события.

Ниже: новая версия методов закрытия окна:

Вы заметили, что мы создали ещё один метод _closeAfterTransition() и перенесли основную логику закрытия туда. Это нужно, чтобы удалить обработчик события transitionend после закрытия окна, ведь в метод removeEventListener необходимо передать именно ту функцию, которую мы привязывали.

Кроме того, если анимация не будет нужна, можно просто вызвать this._closeAfterTransition() не вешая его на событие.

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

2.2 Закрытие окна по клику на оверлей

Нам нужно обработать ещё одно событие – закрытие окна по клику на элемент подложки .hystmodal__wrap . Мы можем повесить обработчик клика на документ для делегирования события как при открытии и проверить что событие произошло на .hystmodal__wrap примерно так:

Это будет работать, но есть один малозаметный недостаток.

Проблема №8. Если кнопку мыши нажать внутри окна, а отпустить за его пределами (над подложкой), окно закрывается.

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

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

Мы могли бы решить это изменением html, добавляя ещё один div сразу после .hystmodal__window и размещая его визуально под окном. Но нам бы не хотелось добавлять лишний пустой div ещё сильнее усложняя разметку.

Мы можем разбить наш addEventListener на два отдельных обработчика: для событий mousedown и mouseup и будем проверять чтобы оба события происходили именно на .hystmodal__wrap . Добавим новые обработчики событий в наш метод eventsFeeler()

2.3 Управление фокусом

У нас заготовлено два метода для управления фокусом: focusContol() для переноса фокуса внутрь окна и обратно при его закрытии, а также focusCatcher(event) для блокирования ухода фокуса из окна.

Решения для фокуса были реализованы аналогично js-библиотеке «Micromodal» (Indrashish Ghosh). А именно:

1. В служебный массив сохраним все css селекторы на которых может быть установлен фокус (свойство помещаем в init()):

2. В методе focusContol() находим первый такой селектор в окне и устанавливаем на него фокус, если окно открывается. Если же окно закрывается – то переводим фокус на this.starter :

3. В методе focusCatcher() находим в окне и превращаем в массив коллекцию всех элементов на которых может быть фокус. И проверяем, если фокус должен был выйти на пределы окна, то вместо этого устанавливаем фокус снова на первый или последний элемент (ведь фокус можно переключать как по Tab так и по Shift+Tab в обратную сторону).

Результирующий код метода focusCatcher:

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

Проблема №9. В IE11 не работают методы Element.closest() и Object.assign() .

Для поддержки Element.closest, воспользуемся полифилами для closest и matches от MDN.

Можно их вставить просто так, но так как у нас проект всё равно собирается webpack, то удобно воспользоваться пакетом element-closest-polyfill который просто вставляет этот код.

Для поддержки Object.assign , можно воспользоваться уже babel-плагином @babel/plugin-transform-object-assign

3. Заключение и ссылки

Повторяя начало статьи, всё изложенное выше, я оформил в маленькую библиотеку hystModal под MIT-лицензией. Вышло 3 кБ кода при загрузке с gzip. Ещё написал для неё подробную документацию на русском и английском языке.

Что вошло ещё в библиотеку hystModal, чего не было в статье:

  • Настройки (вкл/выкл управление фокусом, варианты закрытия, ожидание анимации закрытия)
  • Коллбеки (функции вызывающиеся перед открытием окна и после его закрытия (в них передаётся объект модального окна))
  • Добавлен запрет на какие-либо действия пока анимация закрытия окна не завершится, а также ожидание анимации закрытия текущего окна перед открытием нового (если окно открывается из другого окна).
  • Оформление кнопки-крестика закрытия в CSS
  • Минификация CSS и JS плагинами Webpack.

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

Читайте также: