Базовый accessibility
Несколько лет назад я незаметно пересел с мыши на Trackpad и постепенно стал всё больше пользоваться навигацией с клавиатуры. И как-то раз открыл один из своих старых проектов, попробовал залогиниться и, о, ужас! Форма логина не работала с клавиатуры. Та самая форма, которую я когда-то сдал как готовую фичу.
На первый взгляд кажется, что это крайний случай: кто вообще логинится без мыши. Но после нескольких лет без мыши начинаешь невольно замечать проблемы с клавиатурной навигацией везде. Открываешь форму Tab-ом и сразу видишь, что выделение фокуса исчезло, после нажатия Tab фокус прыгнул не туда, кнопка Submit вообще недоступна без мыши.
Accessibility часто воспринимают как “для людей с ограниченными возможностями”, но точнее это про ситуативные ограничения. На практике базовый уровень не такой большой:
Видимое выделение фокуса. Когда элемент в фокусе, это должно быть заметно. Браузер рисует стандартный outline, который многие разработчики сбрасывают через outline: none и ничего не добавляют взамен.
/* ❌ */
:focus {
outline: none;
}
/* ✅ */
:focus-visible {
outline: 2px solid #0066cc;
}
Логичная последовательность Tab. Порядок, в котором клавиатура обходит элементы, должен совпадать с визуальным порядком на странице. Если макет построен через абсолютное позиционирование или flex с order, порядок в DOM и на экране могут расходиться. Пройди форму Tab-ом — если фокус прыгает непредсказуемо, порядок навигации сломан.
Подписи для иконок-кнопок. Иконка без текста должна иметь aria-label, скринридер объявит её как “button” и замолчит, пользователь не поймёт, что это за кнопка.
<!-- ❌ -->
<button><svg>...</svg></button>
<!-- ✅ -->
<button aria-label="Закрыть"><svg>...</svg></button>
Цветовой контраст. Серый текст на светлом фоне читается плохо — и не только людьми с нарушением зрения: солнечный свет, усталость, маленький экран. Минимум по WCAG: 4.5:1 для обычного текста, 3:1 для крупного. Lighthouse поможет выявить такие проблемы.
Семантика. Кнопка должна быть <button>, а не <div> с onclick. Поле должно быть связано с <label> через for/id: тогда клик по тексту метки фокусирует поле, и скринридер озвучивает её при переходе к нему.
<!-- ❌ -->
<div onclick="submit()">Отправить</div>
<input id="email" />
<!-- ✅ -->
<button type="submit">Отправить</button>
<label for="email">Email</label>
<input id="email" />
alt для изображений. Если картинка несёт смысл, нужен описательный alt. Если декоративная, ставим alt="", чтобы скринридер её пропустил, а не читал имя файла.
<!-- ❌ -->
<img src="chart.png" />
<!-- ✅ смысловая -->
<img src="chart.png" alt="Продажи выросли на 40% в Q3" />
<!-- ✅ декоративная -->
<img src="divider.svg" alt="" />
Не передавать смысл только цветом. Ошибка, выделенная красным без текста или иконки: люди с нарушением цветового восприятия её не заметят.
Ошибки форм. Привязка сообщения об ошибке к полю через aria-describedby позволяет скринридеру озвучить конкретную ошибку, а не просто факт её наличия.
<!-- ❌ -->
<input id="email" aria-invalid="true" />
<p>Введите корректный email</p>
<!-- ✅ -->
<input id="email" aria-invalid="true" aria-describedby="email-error" />
<p id="email-error">Введите корректный email</p>
Skip link. Первая ссылка на странице, визуально скрытая, которая перебрасывает сразу к основному контенту. Без неё пользователи клавиатуры на каждой странице Tab-ают через всю навигацию.
<a href="#main" class="skip-link">Перейти к основному контенту</a>
.skip-link {
position: absolute;
top: -100%;
}
.skip-link:focus {
top: 0;
}
Анимации. Часть пользователей физически плохо переносит анимации на экране. Один медиа-запрос решает это.
@media (prefers-reduced-motion: reduce) {
* {
animation: none !important;
transition: none !important;
}
}
Модальные окна. При открытии фокус переходит на первый элемент формы или кнопку закрытия, при закрытии возвращается на элемент, который модалку открыл. Без этого пользователь теряется в навигации. Звучит очевидно, но на практике часто на это забивают.
Большинство этих проблем не находят просто потому, что про них не думают в процессе разработки и не тестируют. И напрасно, потому что это такая же характеристика продукта, как performance или отсутствие багов, и напрямую влияет на то, насколько удобно им пользоваться.
Кстати, в США из-за нарушений accessibility на сайтах было подано тысячи исков по закону ADA. В Европе European Accessibility Act вступил в полную силу в 2025 году. Во многих странах это уже законодательное требование, а не рекомендация.
← К статьям