5 Most Common ARIA Attribute Mistakes
Breaking down typical ARIA mistakes that make sites less accessible instead of more accessible.
Andrii Vdovyn
ARIA (Accessible Rich Internet Applications) — це набір атрибутів HTML, розроблений W3C, який дозволяє покращити доступність динамічного контенту та інтерфейсів для користувачів з обмеженими можливостями. Але ARIA — це потужний інструмент, який легко використати неправильно. Існує так зване перше правило ARIA: не використовуй ARIA, якщо можна обійтись нативним HTML-елементом або атрибутом. Нативні елементи вже мають вбудовану семантику, клавіатурну підтримку та роботу зі скрінрідерами — без жодного додаткового коду. Специфікацію ARIA офіційно підтримує W3C WAI-ARIA 1.2. У цій статті розглянемо п'ять найпоширеніших помилок при роботі з ARIA — кожна з них безпосередньо порушує конкретні критерії WCAG 2.1.
Помилка 1: aria-label замість нативного тексту
Що це таке. Розробники нерідко додають aria-label до кнопок або посилань, навіть якщо елемент уже має видимий текстовий вміст. Це призводить до розбіжності між тим, що бачить зрячий користувач, і тим, що чує користувач скрінрідера.
Чому це проблема. Коли aria-label присутній, він повністю перекриває видимий текст для асистивних технологій. Якщо два значення не збігаються — виникає плутанина. Користувачі голосового керування також покладаються на видимий текст кнопки, щоб сказати команду вголос — і якщо вона не відповідає aria-label, команда не спрацює.
❌ Неправильно
<!-- aria-label перекриває видимий текст "Надіслати" -->
<button aria-label="Відправити форму">Надіслати</button>
<!-- Іконка-кнопка без будь-якого підпису -->
<button>
<svg><!-- іконка кошика --></svg>
</button>✅ Правильно
<!-- Видимий текст є достатнім описом -->
<button>Надіслати</button>
<!-- Для іконки без тексту — aria-label обґрунтований -->
<button aria-label="Видалити товар з кошика">
<svg aria-hidden="true"><!-- іконка кошика --></svg>
</button>WCAG критерій
2.5.3 Label in Name (рівень A) — видима мітка елемента керування повинна збігатися або бути частиною його доступної назви (accessible name). Невідповідність між видимим текстом і aria-label порушує цей критерій.
Помилка 2: Невірні ARIA-ролі
Що це таке. Розробники часто додають role="button" до елемента <div>, щоб позначити його кнопкою для скрінрідерів. Але вони забувають, що роль — це лише оголошення. Справжня кнопка несе значно більше вбудованої поведінки.
Чому це проблема. Елемент <div role="button"> без tabindex="0" недоступний з клавіатури — на нього не можна перейти клавішею Tab. Крім того, без обробника keydown для Enter і Space клавіатурні користувачі не зможуть його активувати. Нативний <button> робить усе це автоматично.
❌ Неправильно
<!-- Немає tabindex — недоступний з клавіатури -->
<!-- Немає keydown — Enter/Space не активують -->
<div role="button" onclick="submitForm()">
Надіслати
</div>✅ Правильно
<!-- Нативна кнопка: фокус, Enter, Space — все вбудовано -->
<button type="submit" onclick="submitForm()">
Надіслати
</button>
<!-- Якщо div справді необхідний — потрібно все це: -->
<div
role="button"
tabindex="0"
onclick="submitForm()"
onkeydown="if(e.key==='Enter'||e.key===' ')submitForm()"
>
Надіслати
</div>WCAG критерій
2.1.1 Keyboard (рівень A) — весь функціонал має бути доступний з клавіатури. 4.1.2 Name, Role, Value (рівень A) — елементи інтерфейсу повинні мати правильне ім'я, роль і стан.
Помилка 3: aria-hidden="true" на видимий контент
Що це таке. Атрибут aria-hidden="true" повністю прибирає елемент і всіх його нащадків з дерева доступності. Це корисно для декоративних іконок, але катастрофічно, якщо застосовується до важливого контенту.
Чому це проблема. Якщо приховати видимий текст, заголовок або цілий блок — користувачі скрінрідерів не отримають жодної інформації про цей вміст. Особливо небезпечно приховувати інтерактивні елементи: скрінрідер не зможе їх оголосити, але клавіатурний фокус може туди потрапити — це створює так зване «фокус у темряві».
❌ Неправильно
<!-- Весь розділ прихований від скрінрідера,
але видимий на екрані -->
<section aria-hidden="true">
<h2>Акційні пропозиції</h2>
<p>Знижка 30% на всі плани до кінця місяця!</p>
<button>Отримати знижку</button>
</section>
<!-- Кнопка прихована, але отримує фокус -->
<button aria-hidden="true">Видалити акаунт</button>✅ Правильно
<!-- aria-hidden тільки для декоративних елементів -->
<span aria-hidden="true">🎉</span>
<span>Акційні пропозиції</span>
<!-- Декоративна іконка всередині кнопки з текстом -->
<button>
<svg aria-hidden="true" focusable="false">
<!-- іконка зірки -->
</svg>
Додати до обраного
</button>WCAG критерій
1.3.1 Info and Relationships (рівень A) — інформація, структура та зв'язки, передані через презентацію, мають бути програмно визначуваними. 4.1.2 Name, Role, Value (рівень A) — стан елементів має бути доступним для асистивних технологій.
Помилка 4: aria-labelledby вказує на неіснуючий ID
Що це таке. Атрибут aria-labelledby приймає один або кілька ID елементів, текст яких стає доступною назвою поточного елемента. Якщо зазначений ID не існує в DOM — скрінрідер не знаходить відповідний елемент і просто мовчить або оголошує елемент без будь-якої мітки.
Чому це проблема. Форми без доступних міток є однією з найпоширеніших проблем доступності. Коли aria-labelledby вказує на ID, якого немає в документі (через друкарську помилку, видалення елемента або динамічне рендерення), поле вводу залишається повністю без підпису. Це рівнозначно відсутності <label>.
❌ Неправильно
<!-- ID "email-lbl" не існує в DOM!
Скрінрідер не знайде мітку і мовчатиме -->
<label id="emial-lbl">Електронна пошта</label>
<input type="email" aria-labelledby="email-lbl" />
<!-- Другий варіант: елемент з таким ID відсутній -->
<input type="search" aria-labelledby="search-heading" />
<!-- де ж елемент з id="search-heading"? -->
✅ Правильно
<!-- Перевірено: id="email-label" збігається точно -->
<label id="email-label">Електронна пошта</label>
<input type="email" aria-labelledby="email-label" />
<!-- Ще надійніше — використати нативний for/id -->
<label for="user-email">Електронна пошта</label>
<input type="email" id="user-email" />
<!-- Пошук з видимим заголовком як міткою -->
<h2 id="search-heading">Пошук по сайту</h2>
<input type="search" aria-labelledby="search-heading" />Порада для аудиту
Завжди перевіряйте правильність ID через браузерні DevTools або автоматизовані засоби перевірки, такі як axe або Lighthouse. Простий тест: відкрийте консоль і виконайте document.getElementById('your-id') — якщо результат null, посилання зламане.
WCAG критерій
1.3.1 Info and Relationships (рівень A) та 4.1.2 Name, Role, Value (рівень A) — елементи форм повинні мати програмно визначувані мітки. Поле вводу без доступної назви не відповідає цим критеріям.
Помилка 5: Надмірне використання aria-live
Що це таке. Атрибут aria-live змушує скрінрідер автоматично оголошувати зміни вмісту в регіоні. Є два значення: polite (після поточного оголошення) і assertive (негайно, перериваючи). Розробники часто ставлять aria-live на занадто велику кількість елементів або використовують assertive там, де це зовсім непотрібно.
Чому це проблема. Надмірне використання live-регіонів створює «шквал оголошень» — скрінрідер безперервно перериває користувача, щоб повідомити про незначні зміни (лічильник символів, анімація завантаження, оновлення таймера). Значення assertive особливо агресивне: воно перериває те, що користувач зараз читає. Це дезорієнтує та робить сайт практично непридатним для використання зі скрінрідером.
❌ Неправильно
<!-- assertive перериває читання кожну секунду -->
<div aria-live="assertive" id="timer">
Залишилось: 59 секунд
</div>
<!-- polite на кожному полі форми — занадто шумно -->
<div aria-live="polite">
Введено: <span id="char-count">0</span>/500 символів
</div>
<!-- Весь блок новин — live region -->
<section aria-live="polite">
<!-- Оновлюється кожні 30 секунд -->
</section>✅ Правильно
<!-- assertive тільки для критичних помилок -->
<div role="alert" aria-live="assertive" id="error-msg">
<!-- Тут лише справді критичні повідомлення -->
</div>
<!-- polite для підтверджень дій користувача -->
<div aria-live="polite" aria-atomic="true" id="status">
<!-- "Форму успішно надіслано" — тільки після дії -->
</div>
<!-- Таймер без live-region, доступний через aria-label -->
<div
role="timer"
aria-label="Залишилось часу: 59 секунд"
id="timer"
>
59
</div>WCAG критерій
4.1.3 Status Messages (рівень AA) — повідомлення про статус мають бути програмно визначувані без перенесення фокуса. Але вони не повинні надмірно переривати роботу користувача.
Перше правило ARIA: коли НЕ використовувати
Перше правило використання ARIA, сформульоване W3C, звучить так: «Якщо можна використати нативний HTML-елемент або атрибут із потрібною семантикою та поведінкою — використовуйте його замість того, щоб перевизначати елемент і додавати ARIA-роль, стан або властивість для забезпечення доступності».
Ось конкретні ситуації, коли ARIA не потрібна:
role="button"на<div>— замість цього використовуйте<button>role="navigation"на<div>— замість цього використовуйте<nav>role="heading"— замість цього використовуйте<h1>–<h6>aria-required="true"— замість цього використовуйте нативний атрибутrequiredaria-disabled="true"— замість цього використовуйте нативний атрибутdisabled
ARIA дійсно необхідна тоді, коли ви будуєте складні UI-компоненти, для яких не існує нативного HTML-аналога: вкладки (tabs), аккордеони, дерева (tree), комбобокси, слайдери, модальні діалоги з керуванням фокусом. У всіх інших випадках — спочатку подумайте, чи вирішує проблему нативний HTML.
- ARIA доповнює HTML — не замінює його
- Погана ARIA гірша за відсутність ARIA — неправильні атрибути активно заважають скрінрідерам
- Завжди тестуйте зі справжніми скрінрідерами: NVDA, JAWS, VoiceOver
- Автоматичні перевірки (axe, Lighthouse) виявляють лише ~30% проблем доступності
Часті питання
Чи обов'язково використовувати ARIA для відповідності WCAG?
Ні. WCAG не вимагає використання ARIA. Більшість критеріїв WCAG можна виконати за допомогою правильного семантичного HTML. ARIA потрібна лише тоді, коли нативні HTML-елементи не можуть забезпечити необхідну семантику — наприклад, для складних кастомних компонентів. Якщо використати нативну кнопку замість <div role="button">, це і відповідатиме WCAG, і вимагатиме менше коду.
Які інструменти допоможуть знайти помилки ARIA автоматично?
Найпопулярніші інструменти: axe DevTools (розширення для Chrome/Firefox), Google Lighthouse (вбудований у Chrome DevTools), WAVE від WebAIM, та IBM Equal Access Checker. Вони виявляють найбільш поширені проблеми ARIA автоматично. Проте пам'ятайте: жоден автоматичний інструмент не замінює ручне тестування зі скрінрідером.
Чи впливають ARIA-атрибути на SEO?
Безпосередній вплив ARIA на ранжування Google є мінімальним. Однак правильне використання ARIA разом із семантичним HTML покращує структуру документа, яку Google розуміє краще. Крім того, покращення доступності зазвичай позитивно впливає на поведінкові показники (час на сторінці, відмови), а це вже опосередковано сигналізує пошуковикам.
Яка різниця між aria-label, aria-labelledby та aria-describedby?
aria-label — задає текстову мітку безпосередньо у значенні атрибута (використовується, коли видимого тексту немає). aria-labelledby — посилається на ID іншого елемента, текст якого стає міткою (для зв'язку з видимим заголовком або міткою). aria-describedby — посилається на ID елемента з додатковим описом (підказки, інструкції, повідомлення про помилки). Мітка оголошується першою і коротко — опис оголошується після паузи і може бути довшим.
Джерела
- W3C WAI-ARIA 1.2 Specification — офіційна специфікація ARIA від W3C
- ARIA Authoring Practices Guide (APG) — рекомендації W3C щодо патернів використання ARIA
- MDN Web Docs: ARIA — вичерпна документація по ARIA-атрибутах та ролях
- Using ARIA (W3C Working Group Note) — практичний посібник W3C з правилами використання ARIA
- Web Content Accessibility Guidelines (WCAG) 2.1 — міжнародний стандарт доступності веб-контенту