Анна Селезнёва, Evil Martians
Web Standards Days, Минск, 21 октября 2017
Меня зовут Аня, и я марсианка
И пользователи не жаловались
alert('Resistance is futile');
confirm('Resistance is futile');
prompt('Resistance is futile', 'Surrender');
Не используйте alert / confirm / prompt
window.showModalDialog('modal-dialog.html');
<dialog open class="dialog">
<p>Resistance is futile</p>
</dialog>
Показать:
document.querySelector('dialog').showModal();
Спрятать:
document.querySelector('dialog').close();
CSS:
.modal::backdrop {
background-color: rgba(0, 0, 0, 0.7);
}
Пример: codepen.io/askd/pen/zEjOaJ
Спецификации:
Живой стандарт WHATWG HTML
Рабочий черновик HTML5.1
Поддержка:
<div class="modal">
<p>Resistance is futile</p>
</div>
CSS:
.modal { display: none; }
.modal.is-opened { display: block; }
aria-hidden="true"
tabindex="-1"
class="visuallyhidden"
.visuallyhidden {
border: 0;
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
white-space: nowrap;
}
<div class="modal" role="dialog"
aria-labelledby="modalTitle"
aria-describedby="modalDesc"
>
<h2 id="modalTitle">Заголовок окна</h2>
<p id="modalDesc">Описание окна</p>
</div>
<input type="checkbox" id="toggle">
<div class="modal">
...
<label for="toggle">✕</label>
</div>
<label for="toggle">Показать модальное окно</label>
CSS:
#toggle:checked ~ .modal { display: block; }
Пример: codepen.io/askd/pen/QqrPdo
<div class="modal" id="modal">
...
<a href="#">✕</a>
</div>
<a href="#modal">Показать модальное окно</a>
CSS:
#modal:target { display: block; }
Пример: codepen.io/askd/pen/PJyoLZ
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
}
<div class="modal overlay">
<div class="modal-content"> ... </div>
</div>
.modal {
display: flex;
justify-content: center;
align-items: center;
}
<button>✕</button>
или
<span role="button" tabindex="0">✕</span>
<button aria-label="Закрыть">✕</button>
или
<button aria-label="Закрыть" class="close"></button>
function handleKeyDown (event) {
const keyCode = event.keyCode || event.which;
if (keyCode === 27) {
// закрыть модальное окно
event.preventDefault();
}
}
document.addEventListener('keydown', handleKeyDown);
Когда открыто модальное окно, навигация с клавиатуры не должна выходить за его пределы
<div inert>
<input type="text" placeholder="Недоступное поле">
<button>Некликабельная кнопка</button>
</div>
github.com/theKashey/focus-lock
setFocus(topNode, lastNode)
ReactJS:
<FocusLock><Modal /></FocusLock>
Подробнее в статье
.modal {
overflow: auto;
}
body {
overflow: hidden;
}
Мобильная версия
body { position: fixed; }
JS
const top = window.pageYOffset || documentElement.scrollTop;
body.style.top = `-${top}px`;
Если для содержимого требуется скролл, то скорее всего лучше использовать не модальное окно, а отдельную страницу
backdrop-filter: blur(8px);
Поддержка:
-webkit
<div id="app-root"></div>
CSS:
#app-root { overflow: hidden; }
<div id="app-root"></div>
<div id="modal-root"></div>
JS:
ReactDOM.createPortal(modal, modalRoot);
Пример: codepen.io/askd/pen/WZJqMz
Презентация: askd.rocks/pres/modal