Семантическая разметка поможет нам сделать наше модальное окно более удобным и доступным. А правильное использование стилей и скриптов поднимет юзабилити нашего сайта на новый уровень!
Используйте состояние :focus
в ваших стилях. Это улучшит не только модальные окна, но и всё управление сайтом. Часто состояние :focus
, используемое браузером по умолчанию, переписывается css-reset
-стилями, или само по себе недостаточно выделяет активные элементы, или не вписывается в общее оформление сайта.
Хотя, получение фокуса с клавиатуры и наведение указателя мыши – это всё же два различных состояния, и разумно будет дать им собственные, отличные от других стили:
Btn:hover {
background: #f00;
}
:focus {
box-shadow: 0 0 3px rgba(0,0,0,.75);
}
Каждый элемент, способный получить фокус, должен быть стилизован таким образом. В крайнем случае, если вы не хотите использовать свой стиль :focus
, позаботьтесь о том, чтобы сохранить дефолтный стиль браузера – обычно это пунктирное подчёркивание или рамка вокруг активного элемента, имеющего фокус.
При открытии модального окна и перемещении фокуса необходимо сохранять предыдущий активный элемент. Тогда при закрытии модального окна пользователь сможет продолжить своё взаимодействие с сайтом на том же месте, на котором модальное окно заставило его прерваться.
Это работает как подобие закладки. Без такой функции пользователь переместится к началу страницы, и будет вынужден искать нужный ему контент заново, что обескураживает. Проблему сохранения фокуса может решить вот такой скрипт:
var lastFocus;
function modalShow () {
lastFocus = document.activeElement;
}
function modalClose () {
lastFocus.focus(); // place focus on the saved element
}
При появлении модального окна фокус должен переместиться на него или на первый интерактивный элемент в нём. Тогда пользователю не придётся браться за мышь или перебирать клавишей “Tab
” десятки полей и кнопок:
Если ваше модальное окно занимает весь экран, позаботьтесь о том, чтобы элементы управления в основном окне стали на время недоступны. Иначе любой пользователь может продолжить вводить что-то в основное окно, думая при этом, что взаимодействует с модальным. Обеспечить желаемое может скрипт, подобный этому:
function focusRestrict (event) {
document.addEventListener("focus", function(event) {
if (modalOpen && !modal.contains(event.target)) {
event.stopPropagation();
modal.focus();
}
}, true);
}
Закрывая для пользователя основной экран, мы всё же должны обеспечить для него доступ к элементам управления браузером при помощи всё той же кнопки “Tab
”. Такого поведения от нашего окна ожидают и обычные, зрячие пользователи.
Вышеприведённый скрипт предотвращает переход фокуса в основной документ, вместо этого перемещая его обратно к первому элементу модального окна.
Если мы заодно поместим модальное окно в вершину дерева DOM
, сделав его первым потомком
, то комбинация “Shift”+“Tab
” позволит пользователю переключить фокус на элементы управления браузером:
var m = document.getElementById("modal_window"),
p = document.getElementById("page");
//
должен окружать всю страницу, чтобы можно было применить
// aria-hidden="true" к главному контенту при открытии модального окна.
function swap () {
p.parentNode.insertBefore(m, p);
}
swap();
Если вы не можете ни выбрать верхнюю позицию для блока модального окна заранее, ни переместить его в начало дерева при помощи JavaScript
, вы можете зациклить перемещение фокуса между первым и последним активным элементом в модальном окне.
Для этого необходимо сохранять в скрипте их идентификаторы. Когда пользователь нажмёт “Tab” в последнем элементе окна, вы переместите фокус на первый элемент. Нажатие “Shift”+“Tab
” должно обрабатываться зеркально.
Есть и другие варианты обработки перемещения фокуса. Например, вы можете переназначать и использовать в скрипте списки элементов ввода, между которыми разрешён переход фокуса. Или устанавливать tabindex=-1
на скрываемые активные элементы.
Первый и второй методы делают меню и кнопки браузера недоступными при управлении с клавиатуры. При этом походе критичны хорошо заметный элемент закрытия окна и перехват нажатия клавиши “Esc
” с той же целью. Иначе ваш сайт станет ловушкой для пользователей без мыши.
Третий подход сохранит возможность навигации по элементам управления браузером, но может быть весьма накладным с точки зрения быстродействия скрипта, ведь ему придётся перебрать множество активных элементов на сайте, как при открытии модального окна, так и при его закрытии – чтобы вернуть всем элементам основного контента возможность быть выбранными.
Понятно, что при выборе конкретного метода вы должны учесть все рассмотренные нами факторы.
Закрытие
Модальное окно должно легко закрываться. Стандартные диалоги, вызываемые из JavaScript
функцией alert()
, могут быть закрыты нажатием клавиши “Esc
”. Будет хорошим тоном придерживаться этого соглашения при создании собственных диалогов.
Если диалог содержит много активных элементов, то гораздо лучше будет дать пользователю возможность закрыть его нажатием одной клавиши, нежели заставлять его пробегать по всем полям, чтобы добраться до кнопки «Закрыть
»:
Кроме того, многие разработчики позволяют пользователям закрывать окно щелчком на его свободной области. Для этого можно использовать простой скрипт:
mOverlay.addEventListener("click", function(e)
if (e.target == modal.parentNode)
modalClose(e);
}
}, false);
Очевидным исключением из правил будет тот случай, когда вы действительно не хотите, чтобы посетитель продолжал пользоваться вашим сайтом, пока он не введёт нужную информацию в модальном диалоге, скажем, не зарегистрируется или не авторизуется.
Дополнительные меры по обеспечению доступности сайта
Существуют и другие способы помочь пользователям с ограниченными возможностями ориентироваться во Всемирной паутине. Спецификации WAI-ARIA
покрывают все области взаимодействия пользователя с сайтом. В одних случаях достаточно немного дополнить разметку или стили, в других требуется оснастить сайт скриптами.
ARIA-HIDDEN
Устанавливая атрибуту aria-hidden
значение true
, вы можете скрывать содержимое элемента со всеми его дочерними элементами от программ, читающих экран. Необходимо учесть, что ARIA
-элементы не обладают дефолтной стилизацией в браузерах. Чтобы скрыть их от зрячих пользователей, воспользуйтесь следующим CSS
-кодом:
Modal-window {
display: none;
}
Обратите внимание на весьма специфичный селектор. В общем случае мы не хотим прятать абсолютно все элементы с aria-hidden=true. Вспомните предыдущий пример с кнопкой «X
», чтобы понять, что имеется в виду.
ROLE=»DIALOG»
Добавьте свойство role=»dialog»
ко всем элементам, содержащим модальный контент. Это укажет так называемым техническим средствам реабилитации, что данный контент требует реакции пользователя. Описанные нами скрипты, зацикливающие перемещение фокуса ввода между допустимыми активными элементами, отлично дополнят эту разметку.
Для оповещений, требующих от пользователя простого подтверждения, используйте role=»alertdialog»
совместно с теми же скриптами.
ARIA-LABEL
Свойства aria-label
и aria-labelledby
используются совместно с role=»dialog»
. Если ваше модальное окно имеет заголовок, укажите его идентификатор, например: aria-labelledby=modal_header_id
. В противном случае задайте описание диалога в качестве значения свойства aria-label
.
Как насчёт HTML5-диалогов?
На момент написания статьи Google Chrome версии 37
и ночные сборки Firefox
уже научились поддерживать семантический элемент dialog
.
Когда данный элемент станет общеупотребительным, это избавит нас от необходимости проставлять role=dialog
в различных элементах. Пока же мы рекомендуем использовать role
даже при наличии polyfill
-библиотек для обеспечения поддержки устройств чтения экрана.
Замечательно то, что элемент dialog
обладает не только семантическим значением, но и теми свойствами, которые могут заменить применяемые нами сегодня скрипты и стили.
Например, чтобы показать или спрятать диалог, мы обычно используем такой скрипт:
var modal = document.getElementById("myModal"),
openModal = document.getElementById("btnOpen"),
closeModal = document.getElementById("btnClose");
// для показа модального окна
openModal.addEventListener("click", function(e) {
modal.show();
// или
modal.showModal();
});
// для закрытия модального окна
closeModal.addEventListener("click", function(e) {
modal.close();
});
Метод show()
показывает диалог, вместе с тем оставляя пользователю доступ к остальному сайту. Метод showModal()
запускает диалог и запрещает пользователю взаимодействовать с другими элементами сайта.
Модальное окно – маленькое окошко, которое всплывает, чтобы сказать о чем то важном. Сложно ли сделать модальное окно без Bootstrap? Попробуем разобраться.
Куда вставить в DOM?
Обычно, я помещаю его перед закрывающим тэгом body.