A11Y
Доступность
динамических веб
компонентов
Кто я? Что меня связывает с accessibility?
Пара слов о том как работают скринридеры
• JAWS, NVDA, VoiceOver…
• Анализ контента страницы
• Виртуальный курсор
• Горячие клавиши: для хедингов, списков, секций,
ссылок и т.д.
Пара слов о том как тестировать
• Родным скринридером для вашей системы
• Используя виртуальную машину, если надо
• Закрыть глаза
HTML phrasing, sectioning (секционный,
текстовый, встроенный и т.д.)
• Разделить страницу по секциям с заголовками
• Секция имеет role
• Секция, должна иметь хеддинг и aria-labeldby
• Секции желательно иметь абзац с описанием aria-
described-by
<header role=“banner”>
<a href=“/”
rel=“home”>Домашняя страница</a>
<nav role=“navigation”>
<a href=“/about”>О нас</a>
<a href=“/contact”>Контакты</a>
</nav>
</header>
<section role=“main”>
<h1>Заголовок страницы</h1>
<p>Походу это единственный параграф и самое
важное описание на странице.</p>
</section>
<footer role=“contentinfo”>
<p>Копирайт или дата или контакты.</p>
</footer>
HTML - основа доступного интернета
(accessibility)
• Правильный лейаут
• Правильные элементы
• Стили по умолчанию
• Встроенная поддержка клавиш для accessibility
• Например: кнопка - <button/>, а не <div/> или <a/>
• Картинка - <img/>, alt и title
• Акронимы, аббревиатуры, тире и дефисы
Несколько простых примеров
<button/>
• почему не <div/>
• почему не <a/>
• оба и основной поток и интерактивный контент
• скринридер ссылку называет ссылкой, а кнопку кнопкой
• кнопка не обязательно ссылается куда-то
• лучше на мобильном
• хорошо для СЕО
<img/>
• Альтернативный текст
• [alt] аттрибут
• [title] аттрибут
• [longdesc] аттрибут
• <figure/> элемент
CSS и JavaScript
• Если использованы неправильно - портят accessibility
• Контраст должен быть 4.5:1 минимум фона к текста
• Стили не должны сильно менять вёрстку, если только
не описано это правильными атрибутами
• Для функциональных элементов стараться избегать
<div/> а использовать HTML5 элементы
• JavaScript не должен прятать элемент в фокусе из
видимой области.
WAI-ARIA (Accessible Rich Internet Applications)
• aria-live
• aria-atomic
• aria-relevant
• role
• aria-expanded
• aria-labelldby
• aria-describedby
• aria-hidden
<div
role=“log”></div>
role
<div
role=“log”
aria-live=“polite”></div>
aria-live
<div
role=“log”
aria-live=“polite”
aria-relevant=“additions”></div>
aria-relevant
<div
role=“log”
aria-live=“polite”
aria-relevant=“additions”
aria-atomic=“false”></div>
aria-live
<ul>
<li>
<a
href=“#”
aria-expanded=“false”
aria-controls=“text”>Open me</a>
<p id=“text”>Дополнительное описание контента по
ссылке</p>
</li>
</ul>
aria-expanded | aria-controls
<section
role=“region”
aria-labelledby=“title”
aria-describedby=“description”>
<h2 id=“title”>Заголовок региона</h2>
<p id=“description”>Описание региона</p>
</section>
aria-labelledby | aria-describedby
<img
src=“some_cool_icon.png”
alt=“some cool icon”
aria-hidden=“true”/>
aria-hidden
Примеры динамических веб-компонентов
• Выпадающий элемент
• Индикатор загрузки (лоадер, спиннер)
• Бесконечный список
• Автоматический скролл
<ul>
<li aria-live=“polite”>
<a
id=“dropdown-link”
href=“#”
title=“Show details”
aria-controls=“dropdown-content”
aria-expanded=“false”>Show the content</a>
<div
id=“dropdown-content”
class=“visibly-hidden”
aria-labelledby=“dropdown-link dropdown-head”
role=“region”
tabindex=“-1”>
<h3 id=“dropdown-head”>Header</h3>
<p>Super useful descriptive hidden content.</p>
</div>
</li>
</ul>
Выпадающий элемент
<div
id=“notification”
aria-live=“assertive”></div>
Индикатор загрузки (классический пример)
Индикатор загрузки (классический
неправильный пример)
<div
id=“notification”
aria-live=“assertive”
role=“alert”></div>
<div
data-a11y-loader></div>
Индикатор загрузки (как сделать, чтобы это
работало везде)
<div
data-a11y-loader
role=“alert”>Контент загружается.</div>
как только начинается загрузка
<div
data-a11y-loader>Контент загружается.</div>
через ~250мс убираем аттрибут
<div
data-a11y-loader></div>
через ~250мс убираем текст
<div role=“region”>
<h2 id=“animals”> Список фруктов </h2>
<ul
role=“listbox”
aria-labelledby=“animals”
aria-live=“polite”
aria-relevant=“additions removals”>
<li
role=“option”
aria-setsize=“10”
aria-posinset=“5”> яблоки </li>
<li
role=“option”
aria-setsize=“10”
aria-posinset=“6”> апельсины </li>
</ul>
</div>
Бесконечный список
• aria-live и role не передвигают фокус
• автоскролл, должен не происходить, если убирает
фоксированый элемент со страницы, вместо этого,
должна добавляться кнопка
Автоматический скролл и его поведение
Спасибо за внимание!
Вопросы?
Алексей Кобылинский

A11Y: Доступность динамических веб компонентов | Odessa Frontend Meetup #2