-
Используйте атрибут
lang=ru
для тега<html>
. Он помогает скринридерам и парсерам понять, на каком языке страница, и как её озвучивать. Так жеlang
можно указывать для блоков разметки на другом языке, например, если абзац текста на английском. -
Следите за иерархией заголовков. На странице должен быть только один заголовок 1-го уровня, остальные заголовки должны быть вложенными в зависимости от уровня.
<header>
<h1>Страница отчёта</h1>
</header>
<main>
<article>
<h2>Отчёт 1</h2>
</article>
<article>
<h2>Отчёт 2</h2>
<div>
<h3>Подпункт 1</h3>
</div>
</article>
</main>
- Используйте для разметки списков теги
<ul>
,<ol>
,<li>
; для таблиц<table>
,<tr>
,<th>
,<td>
.
<ul>
<li>Первый пункт</li>
<li>Второй пункт</li>
</ul>
<table>
<tr>
<th>Заголовок первого столбца</th>
<th>Заголовок второго столбца</th>
</tr>
<tr>
<td>Данные</td>
<td>Данные</td>
</tr>
<tr>
<td>Данные</td>
<td>Данные</td>
</tr>
</table>
-
Если компонент ведёт на другую страницу, используйте элемент
<a>
независимо от его внешнего вида. Если интерактивный компонент оставляет пользователя на странице, используйте элемент<button>
. -
Для разметки областей страницы используйте теги
<header>
,<main>
,<article>
,<nav>
,<section>
,<footer>
. В отличии от тега<h1>
элемент<header>
можно использовать несколько раз на странице, например, для заголовка модального окна. Так же, несколько раз можно использовать<footer>
,<article>
,<section>
,<main>
. -
Не забывайте использовать редкие теги:
<abbr>
для аббревиатур,<blockquote>
для цитат, группу тегов<dl>
,<dd>
,<dt>
для определений.
<abbr title="Индивидульный налоговый номер">ИНН</abbr>
<dl>
<dt>Кадровый учёт</dt>
<dd>Это учёт кадров</dd>
</dl>
-
Добавляя атрибут
title
для страницы, помимо названия сервиса дополняйте описанием страницы, например: «Экстерн — создание отчёта». -
Не скрывайте элементы при помощи
display:none
, а информативные элементы не добавляйте через:before
или:after
— скринридер не читает элементы скрытые черезdisplay:none
или добавленные через стили. Для визуального скрытия элемента лучше используйте следующие стили:
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
- Если вы не используете необходимый тэг, но хотите придать элементу семантичное значение, не используйте атрибут
role
. Скринридер прочитает элемент как кнопку, но вам придётся добавлять управление фокусом, обработку нажатий клавиш с клавиатуры. Используйте необходимый тэг вместо этого:
/** Плохо */
<div role="button">Нажми на меня!</div>
/** Хорошо! */
<Button>Нажми на меня!</Button>
- Если у инпута нет лейбла, задайте его при помощи
aria-label
:
<Input aria-label="Введите имя (обязательно)" />
- Если нет возможности обернуть
<Input />
в<label>
, используйтеaria-labeledby
:
<label id="label">Я лейбл для поля!</label>
<Input aria-labeledby="label" />
- Если хотите добавить описание элементу, используйте
aria-describedby
:
<span id="button-description">По нажатию на кнопку отправится отчёт, после чего вам придёт уведомление на почту</span>
<Button aria-describedby="button-description">Нажми!</Button>
- Для дизейбла элемента используйте
aria-disabled
, а визуально и интерактивно блокируйте элемент при помощи стилей и JS. Скринридер остановится на этом элементе, тогда как атрибутdisabled
скринридер проигнорирует.
<Input aria-disabled="true"/>
-
Все элементы управления и ввода (те, с которыми может взаимодействовать пользователь) должны быть фокусируемые. Если элемент по умолчанию не имеет фокуса - можно сделать его фокусируемым при помощи атрибута
tabindex=”0”
. -
Если при взаимодействии с контентом страницы открывается
<Modal>
или<SidePage>
, то при нажатии наtab
должен фокусироваться контент модального окна\сайдпейджа в первую очередь, на первый интерактивный элемент или на заголовок в случае скрин-ридера. -
Тестируйте выполнение основных сценариев с клавиатуры: перемещение при помощи
tab
,shift+tab
, управление контролами при помощи стрелочек клавиатуры,enter
,escape
. -
Не блокируйте зум на сайте. Делайте странички сайта адаптивными для изменений масштабирования. Поддерживайте масштабирование минимум до 150%.
-
При переключении клавишей
tab
элементы формы должны переключаться в нужной последовательности, один за одним. -
Не злоупотребляйте атрибутом tabindex. Если на странице появятся новые элементы, легко запутаться в установленных значениях. При ошибках использования, например, повторяющихся значениях tabindex, навигация по DOM путается — пользователю скринридера будет сложно перемещаться по странице.
-
Старайтесь чтобы визуальное расположение элементов на сайте повторялось в разметке, DOM-дереве. Есть стили (например,
flex-direction: row-reverse
), которые меняют визуальный порядок элементов на странице. При это вDOM
порядок остаётся прежним, и скринридер прочитает его как вDOM
, но на странице эти элементы будут расположены по-другому. Это же правило касается блоков сposition: absolute | sticky | fixed
– стилей, выносящих блоки из потока.
-
Оставляйте пустой атрибут
alt
для декоративных картинок и заполняйте его для информативных элементов. Не стоит писать вalt
большие объёмы текста, в общих чертах описывайте самое важное. -
Для сложных изображений\графиков дублируйте информацию в текстовом варианте.
<picture>
<img src=".../images/graph.png" alt="На графике изображено количество принятых отчётов с первого раза. С первого раза принимаются 80% отчётов за год, 10% со второй попытки и оставшиеся 10% с третьей или больше.">
</picture>
-
Не используйте символ * как обозначение обязательности поля:
Ваше имя*:
Лучше явно подписать обязательность:
Ваше имя (обязательно):
Либо явно написать «обязательные поля обозначены символом *»
Дело в том, что символ * голосовые ассистенты читают как «star» или «звёздочка», в зависимости от языка
-
Лучше всего валидировать формы по нажатию на кнопку
submit
, в случае ошибки переносить фокус на текст ошибки. Если же валидация формы происходит после потери фокуса, пользователь скринридера не узнает об этом. Ему придётся искать ошибку наугад. -
Текст об ошибке лучше размещать рядом с полем, визуально отделять его цветом и иконкой. Так же, текст ошибки лучше размещать в
<label>
этого поля, для того, чтобы после фокусировки на поле при помощи скринридера, он прочитал ошибку и пользователь мог исправить проблему.
<h1>Пользовательские данные</h1>
<span>Обязательные поля обозначены символом *</span>
<form>
<label htmlFor="name">Имя* {isNameError && "содержит ошибку"}</label>
<Input id="name" placeholder="Введите ваше имя" />
<label htmlFor="lastname">Фамилия {isLastNameError && "содержит ошибку"}</label>
<Input id="lastname" placeholder="Введите вашу фамилию" />
<Button onClick={checkErrors}>Отправить</Button>
</form>
- В кнопку-иконку добавьте текст с описанием действия и скройте его с помощью специального класса. Этим же способом можно подписывать отдельно стоящие иконки.
<Button>
<Icon />
<span className="visually-hidden">Нажми на меня!</span>
</Button>
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
- Указывайте
<label>
для каждого поля формы. Если поле нельзя обернуть в<label>
, используйте атрибутыhtmlFor
иid
:
<label htmlFor="input-id">Имя Фамилия</label>
<input id="input-id"/>
Либо используйте aria-label
:
<input aria-label="Имя Фамилия" id="input-id"/>
Основывайте собственные компоненты на встроенных компонентах браузера — они учитывают все кейсы и сложности работы с компонентом, особенно работу с клавиатуры. Реализуйте стандартные паттерны.
-
Браузеры имеют встроенные инструменты проверки вёрстки на контрастность и семантику разметки. Используйте их при вёрстке.
-
Расширение браузера aXe проверит и выведет ошибки в панель разработчика браузера. Также его можно внедрить как шаг в CI.
-
Расширение Lighthouse от Google позволяет провести аудит сайта на основные правила доступности.
-
@storybook/addon-a11y — аддон для Storybook, находящий ошибки в вёрстке, а также позволяющий имитировать некоторые заболевания глаз.
-
eslint-plugin-jsx-a11y — плагин для ESLint, проверяющий код на доступность.
-
jest-axe — инструмент для написания тестов на доступность.