Привет! Представляю вашему вниманию перевод статьи "Meet the New Dialog Element" автора Keith J. Grant.
HTML 5.2 представил новый элемент dialog для нативных модальных окон. На первый взгляд, он кажется довольно простым (так и есть), но поигравшись с ним я обнаружил, что он имеет несколько замечательных возможностей, которые легко упустить.
Я встроил полноценное демо в конец статьи, но если вы захотите взглянуть на него во время чтения, вы можете найти его здесь.
Вот пример базовой разметки для окна диалога:
<dialog open>
Native dialog box!
</dialog>
Атрибут open означает, что диалог виден. Без этого атрибута диалог будет скрыт до тех пор, пока вы не используете JavaScript, чтобы он стал видимым. Без всякой стилизации диалог выглядит следующим образом:
На странице он спозиционирован абсолютно, так что он появится впереди всего контента, как можно ожидать, и он горизонтально центрирован. По умолчанию, его ширина равна ширине контента внутри.
Базовые операции
В JavaScript есть несколько методов и свойств для облегчения работы с элементом dialog. showModal() и close() — два метода, которые, возможно, понадобятся вам больше всего.
const modal = document.querySelector('dialog');
// показывает диалог (добавляет атрибут "open")
modal.showModal();
// скрывает диалог (удаляет атрибут "open")
modal.close();
Когда вы используете showModal() для открытия диалога, на страницу добавляется фон, блокирующий взаимодействие пользователя с контентом вне модального окна. По умолчанию фон полностью прозрачный, но вы можете сделать его видимым с помощью CSS (подробнее об этом ниже).
Нажатие Esc закроет диалог, а также вы можете создать кнопку закрытия с вызовом метода close().
Есть еще третий метод, show(), который также показывает модальное окно, но без сопутствующего фона. Пользователь сможет взаимодействовать с элементами за пределами диалога.
Поддержка браузерами и полифилл
На данный момент dialog поддерживается только в Chrome. Firefox предоставляет базовую стилизацию, однако для применения JavaScript API пользователь должен явно включить эту функцию. Я думаю, в скором времени Firefox включат его по умолчанию.
Благо, у нас есть полифилл, который поддерживает и поведение JavaScript, и стилизацию по умолчанию. Для его использования установите dialog-polyfill в npm, или используйте старый добрый тег script. Полифилл работает в IE9 и выше.
При использовании полифилла, каждый диалог на странице должен быть инициализирован:
dialogPolyfill.registerDialog(modal);
Этот прием не заменит нативное поведение диалога для браузеров, которые поддерживают его.
Стилизация
Открывать и закрывать модальное окно приятно, однако это выглядит не очень профессионально. Добавить стилизацию так же просто, как и стилизовать любой другой элемент. Фон может быть стилизован с помощью нового псевдоэлемента ::backdrop.
dialog {
padding: 0;
border: 0;
border-radius: 0.6rem;
box-shadow: 0 0 1em black;
}
dialog::backdrop {
/* сделает фон черным полупрозрачным */
background-color: rgba(0, 0, 0, 0.4);
}
Для старых браузеров, использующих полифилл, этот псевдоэлемент не сработает. В этом случае полифилл добавляет элемент .backdrop, который следует прямо за диалогом. Вы можете стилизовать его с помощью CSS как-то так:
dialog + .backdrop {
background-color: rgba(0, 0, 0, 0.4);
}
Добавим немного больше разметки для стилизации. Общепринятый подход: разбить диалоговое окно на заголовок, тело и подвал:
<dialog id="demo-modal">
<h3 class="modal-header">A native modal dialog box</h3>
<div class="modal-body">
<p>Finally, HTML has a native dialog box element! This is fantastic.</p>
<p>And a polyfill makes this usable today.</p>
</div>
<footer class="modal-footer">
<button id="close" type="button">close</button>
</footer>
</dialog>
Добавив немного CSS, вы можете сделать так, чтобы модальное окно выглядело точно так, как вам нужно:
Больше контроля
Частенько мы хотим немного обратного взаимодействия с пользователем через диалоговое окно. Когда диалог закрывается, вы можете передать строковое значение в метод close(). Это значение присваивается свойству returnValue DOM-элемента dialog, так что вы можете прочесть его позже:
modal.close('Accepted');
console.log(modal.returnValue); // выведет `Accepted`
Также есть другие события, к которым вы можете подписаться. Два очень полезных: close (срабатывает при закрытии окна) и cancel (срабатывает при нажатии Esc для закрытия окна).
Единственная недостающая вещь — возможность закрыть модальное окно при клике на фон, но есть обходной путь. Клик по фону вызывает событие клика на dialog как на целевом элементе. И если вы создадите диалог так, что дочерние элементы будут заполнять все пространство диалогового окна, эти дочерние элементы будут целевыми для любых кликов внутри диалога. Таким образом, вы можете подписаться на события клика по диалогу, и закрыть его когда непосредственной целью клика будет само окно диалога:
modal.addEventListener('click', (event) => {
if (event.target === modal) {
modal.close('cancelled');
}
});
Это не идеально, но работает. Пожалуйста, дайте мне знать, если найдете лучший способ отслеживания кликов по фону.
Рабочее демо
Я много поработал над демо ниже. Поиграйтесь с ним и увидите, что еще можно делать с элементом dialog. Демо включает полифилл, так что оно будет работать в большинстве браузеров.
Ссылка на демо.
Автор: Нелли Гарбузова