Веб‑доступность (a11y) — это качество интерфейса, при котором пользователи могут воспринимать контент и управлять сайтом с клавиатуры, скринридера, увеличения и других ассистивных технологий. Для разработчика это набор проверяемых критериев: семантика, фокус, контраст, подписи, предсказуемая навигация и корректные состояния. Ниже — практический чек‑лист, анти‑паттерны и процесс внедрения.
Краткий обзор ключевых принципов доступности
- Делайте интерактивные элементы управляемыми с клавиатуры и с видимым фокусом.
- Используйте HTML‑семантику по назначению; ARIA — только когда семантики не хватает.
- Связывайте метки и элементы управления, сообщайте об ошибках форм понятно и однозначно.
- Соблюдайте читаемость: достаточный контраст, масштабирование, понятные заголовки.
- Обеспечивайте предсказуемость: порядок табуляции, логичная структура страницы, корректные роли.
- Тестируйте сочетанием автоматизации и ручных сценариев на ключевых пользовательских потоках.
Почему доступность важна: стандарты, риски и выгоды
Доступность сайта — это не отдельная «фича», а качество реализации UI, при котором люди с разными ограничениями (зрение, моторика, когнитивные особенности, временные ограничения) могут пройти основные сценарии без барьеров. На практике это означает: структура документа понятна, элементы управления подписаны, управление не завязано на мышь, а состояние интерфейса корректно озвучивается.
Обычно ориентиром служат wcag 2.1 требования: воспринимаемость, управляемость, понятность и надежность. Даже если вы не делаете формальную сертификацию, эти принципы удобно переводятся в тестируемые критерии на уровне компонентов и страниц.
Выгоды для продукта и команды: меньше «невоспроизводимых» багов из‑за фокуса/ролей, лучшее качество верстки и компонентной библиотеки, более стабильная UX‑логика. Риски игнорирования: блокирующие дефекты в критических сценариях (логин, платеж, оформление), дорогостоящие переделки в конце цикла, а также претензии со стороны заказчиков, которым нужен аудит доступности сайта под требования закупок или комплаенса. Системная разработка доступного сайта снижает эти риски, потому что критерии становятся частью Definition of Done.
Чек‑лист для фронтенда: обязательные проверки перед релизом
Ниже — минимальный набор проверок, которые можно выполнить на уровне страницы/фичи за один прогон. Старайтесь фиксировать результат не «в целом ок», а конкретно: где фокус, какое имя у элемента, что озвучивает скринридер, можно ли завершить сценарий без мыши.
Минимальный чек‑лист перед релизом (проверяемые пункты)
- Клавиатура: весь сценарий выполняется только Tab/Shift+Tab/Enter/Space/стрелками (где уместно), без ловушек фокуса и без «пропадающих» элементов.
- Видимый фокус: индикатор фокуса заметен на всех интерактивных элементах, включая кастомные компоненты и элементы в модалках.
- Порядок табуляции: порядок соответствует визуальному и смысловому чтению; избегайте положительных
tabindexи внезапных прыжков по DOM. - Семантика: кнопки —
<button>, ссылки —<a href>, списки —<ul>/<ol>, заголовки — по иерархии; интерактив не «маскируется» под<div>. - Доступные имена: у каждого элемента управления есть программно определяемое имя (видимый текст, связанная метка,
aria-label/aria-labelledby— по необходимости), без дублей и бессмысленных «кнопка, кнопка». - Ошибки и подсказки: сообщения об ошибках понятны, не завязаны только на цвет, привязаны к полю и доступны при озвучивании.
- Динамика: раскрытия/аккордеоны/меню отражают состояние (
aria-expandedгде требуется), скрытый контент не табается, изменение состояния не «ломает» фокус.
Быстрые практические советы (встроить в привычку)
- Каждую новую фичу один раз пройдите только Tab/Shift+Tab до завершения сценария (без мыши).
- Если тянет поставить
roleилиaria-*— сначала проверьте, нет ли нативного тега/атрибута, который решает задачу проще и надежнее. - Любой клик по
<div>считайте подозрительным: почти всегда нужен<button>(действие) или<a href>(переход). - Ссылка только для навигации
Если элемент меняет состояние на странице (фильтр, сортировка, лайк) — это чаще кнопка, а не<a>. - Label и имя элемента
Поле должно иметь программно определяемую метку. Для кастомного контрола убедитесь, что доступное имя действительно читается и уникально. - ARIA не «чинит» плохую структуру
role="button"на<div>— это минимум, но вы обязаны добавитьtabindex="0", обработку клавиш и состояния. Чаще дешевле и надежнее заменить на нативный элемент. - Связь управления и контента
Для раскрывающихся блоков: триггер хранит состояние (aria-expanded), а контент имеет идентификатор и связан (например, черезaria-controls), чтобы скринридер понимал, что именно меняется.
Семантика и ARIA: правила применения и частые ошибки
Правило по умолчанию: сначала нативная семантика и корректное поведение, затем — ARIA как «клей» для связей и состояний. Ниже — типовые сценарии, где разработчики чаще всего ошибаются.
- Кнопка против ссылки:
<a>— для переходов,<button>— для действий. Подмена ломает ожидания клавиатурной навигации и озвучивания. - Иконки без текста: если видимого текста нет, задайте доступное имя через
aria-labelилиaria-labelledby, а декоративные SVG/иконки пометьте как скрытые для AT, чтобы не засорять озвучку. - Аккордеон/раскрытие: триггер — кнопка; состояние —
aria-expanded; контент — связан идентификатором (например, черезaria-controls). Ошибка: «раскрытие» на<div>без состояния и без клавиш. - Модальное окно: обеспечьте перевод фокуса внутрь при открытии и возврат на инициатор при закрытии; содержимое под оверлеем не должно быть доступно для табуляции. Ошибка: модалка визуально есть, но фокус уходит на фон.
- Ошибки формы: текст ошибки должен быть связан с конкретным полем (через
aria-describedbyили нативные механизмы), а не существовать «где-то сверху». Ошибка: подсветка красным без текста и без связки. - Роли ради ролей: не назначайте
roleнативным элементам без причины (например,role="button"на<button>), и избегайте конфликтующих ролей. Ошибка: ARIA ухудшает поведение вместо улучшения.
Типовые анти‑паттерны, которые ломают доступность
- Отключенный outline без замены: пользователь клавиатуры теряет позицию фокуса, сценарий становится невыполнимым.
- Модалка без удержания фокуса: Tab уходит под оверлей, фокус пропадает в «подложке», закрыть невозможно.
- Кликабельные
<div>/<span>без клавиатурной поддержки: «работает мышью» не означает «доступно». - Плейсхолдер вместо метки: текст исчезает при вводе, озвучивание непредсказуемо, повышается когнитивная нагрузка.
- Сообщение об ошибке только цветом: пользователь не понимает причину и способ исправления.
- Непредсказуемый порядок табуляции: элементы прыгают из‑за
tabindexили DOM‑перестановок.
- Плюс «быстрых» решений: ускоряют верстку здесь и сейчас.
- Ограничение: почти всегда создают долг — их сложно покрыть тестами и дорого чинить после релиза, особенно если компонент разошелся по проекту.
Тестирование a11y: автоматизация, ручные сценарии и приоритеты

Сочетайте автоматические проверки и ручные проходы: автоматизация ловит часть структурных проблем, ручной прогон — блокеры сценариев. Под тестированием доступности сайта разумно понимать именно эту связку, а не один инструмент.
- Миф: «линтер/сканер гарантирует соответствие» — автоматизация не проверит смысл текста ссылок, логичность порядка фокуса и качество сообщений об ошибках.
- Ошибка: тестировать только главную — проверяйте ключевые потоки: вход, поиск, оформление, оплата, профиль.
- Приоритизация дефектов — сначала блокеры (невозможно выполнить действие), затем деградации (можно, но сложно), затем косметика.
- Ловушка: «починим ARIA» — если компонент изначально несемантичен, сначала меняйте базовый HTML/поведение, потом добавляйте ARIA при необходимости.
- Ручной минимум — клавиатура, проверка фокуса, чтение ключевых экранов скринридером (хотя бы одного), проверка форм на ошибки и подсказки.
Встраивание требований доступности в рабочий процесс и CI
Мини‑сценарий «из концепции в практику»: вы добавили новый фильтр в каталоге, который открывает панель с множественным выбором. Цель — не допустить регрессий по фокусу, имени элементов и состояниям при каждом PR.
Локальные правила для PR (коротко и проверяемо)
- Компонент фильтра реализован нативно: триггер —
<button>, опции сгруппированы через<fieldset>/<legend>и корректные элементы управления, без «кликабельных дивов». - При открытии панели фокус переходит внутрь; при закрытии возвращается на триггер.
- Состояние «открыто/закрыто» отражено на триггере (
aria-expanded), а скрытый контент не участвует в табуляции.
Псевдопроцесс в CI (без привязки к инструменту)

pipeline:
- build
- unit-tests
- a11y-smoke:
run: scan(routes = ["/", "/catalog", "/checkout"])
fail_on: new_critical_or_blocker_issues
- e2e-keyboard:
run: scenario("checkout with keyboard only")
Такой подход превращает доступность в контракт качества: требования понятны, проверяются на каждом изменении, а команда не полагается на разовые героические правки перед релизом.
Короткие ответы на типичные затруднения разработчика
Нужно ли применять WCAG буквально к каждому пикселю?
Ориентируйтесь на критерии как на проверяемые требования, но внедряйте их через компоненты и ключевые сценарии. Практически важнее убрать блокеры (клавиатура, формы, фокус), чем отполировать второстепенные экраны.
Когда ARIA действительно нужна?
Когда вы реализуете кастомный компонент, для которого нет нативного тега, и вы готовы полностью воспроизвести поведение (клавиши, фокус, состояния). Если есть нативный элемент — используйте его.
Можно ли скрыть фокус, чтобы было красивее?
Нельзя убирать видимый индикатор фокуса без равноценной замены. Это прямой риск сделать интерфейс непроходимым для пользователей клавиатуры.
Чем плох плейсхолдер вместо лейбла?
Плейсхолдер исчезает при вводе и не заменяет метку, из‑за чего ухудшается понимание и озвучивание. Лучше оставить постоянную метку, а плейсхолдер использовать как пример формата.
Что важнее: контраст или семантика?
Это разные классы проблем: контраст влияет на воспринимаемость, семантика — на понимание и навигацию ассистивными технологиями. В приоритете — то, что блокирует выполнение сценария у ваших пользователей.
С чего начать, если проект уже большой?
Начните с компонентной библиотеки и самых важных потоков, добавьте клавиатурный прогон как обязательную проверку в PR. Затем расширяйте покрытие на страницы с высокой посещаемостью и критическими формами.
