Доступне модальне вікно
Оновлено 14 жовтня 2026 · 6 хв читання
Спливні вікна розсилки, швидкий перегляд, посібники з розмірів, накладки «Додано в кошик», форми входу, налаштування cookie — інтернет-магазини повні модальних вікон, і це одна з найпоширеніших причин, чому користувачі клавіатури й програм зчитування з екрана застрягають. Ця сторінка показує правильний патерн. Вона входить до серії доступні UI-патерни.
Коли використовувати модальне вікно
APG визначає діалог як «вікно, накладене на основне вікно або інше вікно діалогу», і каже: «вікна під модальним діалогом неактивні» — користувачі не можуть взаємодіяти зі сторінкою, доки діалог не закриється. Використовуйте модальне вікно, коли користувач має завершити чи відхилити завдання, перш ніж іти далі: підтвердити видалення, увійти, обрати варіант у швидкому перегляді. Для інформації, що не блокує завдання (повідомлення «Додано в кошик»), немодальне повідомлення або повідомлення про статус зазвичай менш нав'язливі.
Відповідні критерії WCAG
- 2.1.1 Клавіатура (A) і 2.1.2 Повне керування з клавіатури (A): діалогом можна користуватися та його можна закрити з клавіатури. Утримувати фокус усередині модального вікна припустимо, поки користувач може його залишити.
- 2.4.3 Порядок переміщення фокуса (A): фокус переходить у діалог, а після нього повертається до тригера.
- 2.4.11 Фокус не перекрито (мінімальні вимоги) (AA): W3C зазначає, що правильно побудоване модальне вікно завжди проходить, а немодальні накладки можуть ховати елемент у фокусі.
- 4.1.2 Назва, роль, значення (A): роль dialog і назва.
- 1.3.1 Інформація та взаємозв'язки (A): заголовок є справжнім заголовком, структура — у коді.
- 1.4.10 Прокрутка в кількох напрямках (AA): діалог вміщується на вузькому екрані й за масштабу 400 % без двовимірної прокрутки.
- 2.2.1 Налаштування часу (A): спливні вікна не повинні закриватися за таймером, перш ніж користувачі встигнуть їх прочитати.
Приклад коду
<button type="button" id="open-size-guide">Таблиця розмірів</button>
<dialog id="size-guide" aria-labelledby="size-guide-title">
<h2 id="size-guide-title">Таблиця розмірів</h2>
<table>…</table>
<button type="button" id="close-size-guide">Закрити</button>
</dialog>
<script>
const dialog = document.getElementById('size-guide');
document.getElementById('open-size-guide')
.addEventListener('click', () => dialog.showModal());
document.getElementById('close-size-guide')
.addEventListener('click', () => dialog.close());
</script>
Що робить нативний елемент за стандартом HTML:
showModal()поміщає діалог у верхній шар, блокує документ, так що решта стає неактивною, запам'ятовує елемент, який був у фокусі раніше, і виконує кроки фокусування діалогу, що враховують атрибутautofocus.- Запит на закриття (наприклад, Escape) викликає подію
cancel, яку можна скасувати, а потім закриває діалог. Атрибутclosedbyвизначає, чи закривають його також кліки поза ним. close()повертає фокус на елемент, що був у фокусі раніше, якщо діалог був модальним.
Якщо ви будуєте діалог самостійно через ARIA, дотримуйтеся APG: контейнер має role="dialog", aria-modal="true" і aria-labelledby, що вказує на видимий заголовок; aria-describedby необов'язковий і краще його не вказувати, коли вміст містить списки чи таблиці. Тоді вам доведеться самим зробити тло неактивним, утримувати Tab усередині діалогу, обробляти Escape і відновлювати фокус.
Взаємодія з клавіатури
З патерну діалогу (модального) APG:
| Клавіша | Функція |
|---|---|
| Tab | Наступний елемент діалогу, на який можна перейти клавішею Tab; з останнього — знову на перший |
| Shift + Tab | Попередній елемент діалогу, на який можна перейти клавішею Tab; з першого — на останній |
| Escape | Закриває діалог |
Фокус під час відкриття: «фокус переходить на елемент, що міститься в діалозі», зазвичай на перший елемент, що може отримати фокус. Фокус під час закриття: він «повертається до елемента, що викликав діалог», якщо тільки цього елемента вже не існує, — тоді на інший елемент, що зберігає логічний робочий процес. Після «Видалити товар», наприклад, фокус може перейти на заголовок кошика.
Типові помилки в інтернет-магазинах
- Спливне вікно розсилки під час завантаження сторінки, яке краде фокус, не має назви й кнопки закриття, досяжної з клавіатури.
- Кнопка закриття «×» без доступної назви або іконка закриття, що є
div. - Фокус лишається за накладкою: Tab ходить сторінкою під темним тлом.
- Немає Escape і немає видимого способу закрити на мобільному, коли діалог довший за екран.
- Фокус губиться після закриття, стрибаючи на початок сторінки замість кнопки «Швидкий перегляд».
- Діалоги швидкого перегляду, що перебудовують сторінку товару із дубльованими ID та вкладеними формами.
- Банери cookie, які ні модальні, ні не заважають, а закривають елемент у фокусі внизу екрана, — це порушення 2.4.11 за версією W3C.
Що знаходить автоматична перевірка, а що — ручне тестування
| Автоматично (правило axe-core) | Що знаходить |
|---|---|
aria-dialog-name |
role="dialog" або alertdialog без назви |
button-name |
Кнопки закриття без назви |
aria-hidden-focus |
Елементи з можливістю фокуса всередині вмісту, прихованого через aria-hidden="true" |
aria-hidden-body |
aria-hidden="true" на елементі body |
aria-valid-attr-value |
aria-labelledby, що вказує на відсутній ID |
color-contrast, target-size |
Низький контраст і малі цілі всередині відкритого діалогу |
Усі вони є картками в нашій бібліотеці правил. Щотижневе сканування бачить сторінку такою, якою вона завантажується: закритий діалог не тестується, а спливне вікно, що відкривається саме, — тестується. За допомогою розширення для браузера можна відкрити діалог, а потім запустити перевірку. Ручне тестування: відкрийте діалог з клавіатури, пройдіть його клавішею Tab до кінця й назад, натисніть Escape, перевірте, куди потрапляє фокус, збільште до 400 % і послухайте, як його оголошує програма зчитування з екрана. Кроки — у матеріалі як тестувати WCAG.
Запустіть безкоштовну перевірку однієї сторінки. Це автоматична перевірка, а не повний аудит.
Часті запитання
Що робить модальне вікно доступним?
Фокус переходить у діалог під час відкриття, Tab і Shift + Tab лишаються всередині нього, Escape його закриває, фокус повертається на кнопку, що його відкрила, вміст позаду неактивний, а діалог має назву з видимого заголовка.
Чи варто використовувати HTML-елемент dialog?
Для модального вікна елемент dialog, відкритий через showModal(), робить значну частину роботи: стандарт HTML поміщає його у верхній шар, робить решту документа неактивною, керує початковим фокусом і закриває його за запитом на закриття, наприклад Escape. Перевірте його в браузерах і програмах зчитування з екрана, якими користуються ваші клієнти.
Куди має переходити фокус, коли відкривається діалог?
APG каже, що фокус переходить на елемент усередині діалогу, зазвичай на перший елемент, що може отримати фокус. Для довгого тексту може бути краще поставити фокус на початок вмісту. В елементі dialog це обирають атрибутом autofocus.
Чи є банер cookie модальним вікном?
Лише якщо його так побудовано. Немодальний банер не повинен ховати елементи у фокусі: W3C каже, що закріплений банер cookie не відповідає 2.4.11 «Фокус не перекрито», якщо повністю закриває компонент, який отримує фокус.
Чи може автоматична перевірка протестувати модальне вікно?
Частково. Вона знаходить діалоги без назви, кнопки закриття без назви та елементи з можливістю фокуса, приховані через aria-hidden. Вона не може перевірити переміщення фокуса, пастку фокуса чи Escape, а закритий діалог не перевіряється взагалі.
Джерела
- W3C WAI, APG Dialog (Modal) pattern: https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
- WHATWG, HTML Living Standard, the dialog element: https://html.spec.whatwg.org/multipage/interactive-elements.html#the-dialog-element
- W3C, Understanding 2.4.11 Focus Not Obscured (Minimum): https://www.w3.org/WAI/WCAG22/Understanding/focus-not-obscured-minimum.html