Как тестировать доступность: автоматика, ручная проверка и чеклист
Что находят автоматические инструменты и что нет, тесты с jest-axe и Playwright, ручная проверка за 15 минут, команды скринридеров и чеклист перед релизом

Часть 8 из 8 серии «Доступный веб на практике». Предыдущая часть: Доступность в React: id, фокус при смене маршрута и объявления.
Автоматические проверки находят чуть больше половины проблем доступности. В заключительной части серии — как выстроить проверку в три слоя, что проверять руками за 15 минут и чеклист, который стоит пройти перед каждым релизом.
Как тестировать
Автоматика: нужна, но недостаточна
Автоматические инструменты находят не всё. Deque, авторы движка axe-core, проанализировали данные аудитов (более 13 000 страниц и почти 300 000 проблем) и получили, что автоматические тесты выявили 57,4% проблем по количеству (Deque). Остальное — смысл alt-текста, логичность порядка фокуса, понятность ошибок, поведение виджетов — требует человека.
Поэтому разумная схема — три слоя: линтер при написании кода, автоматические тесты в CI, ручная проверка ключевых сценариев.
Инструменты в браузере:
- Lighthouse (встроен в Chrome DevTools) — быстрая оценка, проверяет подмножество правил axe;
- axe DevTools — расширение от Deque, подробнее Lighthouse;
- WAVE — расширение от WebAIM, наглядно показывает проблемы прямо на странице;
- Accessibility panel в DevTools — дерево доступности, вычисленные имена и роли.
Юнит-тесты. Testing Library подталкивает к доступности сама: запросы getByRole и getByLabelText находят элементы так же, как скринридер. Если тест не может найти кнопку через getByRole('button', { name: 'Отправить' }) — её не найдёт и пользователь.
// Vitest/Jest + Testing Library + jest-axe
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { axe, toHaveNoViolations } from 'jest-axe';
import { expect, test } from 'vitest';
import { ContactForm } from './ContactForm';
expect.extend(toHaveNoViolations);
test('форма не содержит нарушений axe', async () => {
const { container } = render(<ContactForm />);
expect(await axe(container)).toHaveNoViolations();
});
test('ошибка связана с полем и фокус уходит к нему', async () => {
const user = userEvent.setup();
render(<ContactForm />);
await user.click(screen.getByRole('button', { name: 'Отправить' }));
const email = screen.getByLabelText('Электронная почта');
expect(email).toHaveAttribute('aria-invalid', 'true');
expect(email).toHaveAccessibleDescription(/символ @/);
expect(email).toHaveFocus();
});
(toHaveAccessibleDescription и toHaveFocus — из @testing-library/jest-dom.)
End-to-end. Проверка целых страниц в Playwright с @axe-core/playwright:
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';
test('главная страница без нарушений WCAG A/AA', async ({ page }) => {
await page.goto('/');
const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'wcag22aa'])
.analyze();
expect(results.violations).toEqual([]);
});
test('модальное окно: фокус внутри, Esc закрывает, фокус возвращается', async ({ page }) => {
await page.goto('/');
const opener = page.getByRole('button', { name: 'Записаться на консультацию' });
await opener.click();
const dialog = page.getByRole('dialog', { name: 'Запись на консультацию' });
await expect(dialog).toBeVisible();
await expect(dialog.getByLabel('Имя')).toBeFocused();
await page.keyboard.press('Escape');
await expect(dialog).toBeHidden();
await expect(opener).toBeFocused();
});
Ручная проверка за 15 минут
Для каждого ключевого сценария (оформить заказ, оставить заявку, найти контакты):
- Только клавиатура. Пройдите сценарий без мыши. Виден ли фокус на каждом шаге? Логичен ли порядок? Нет ли ловушек? Открываются и закрываются ли меню и модалки?
- Масштаб 200% и 400%. Ничего не наезжает, нет горизонтальной прокрутки, ничего не обрезано.
- Структура. Посмотрите список заголовков и ориентиров (расширение или ротор скринридера) — понятна ли страница по ним одним?
- Скринридер. Пройдите сценарий хотя бы одним скринридером. Минимальный набор команд:
| VoiceOver (macOS) | NVDA (Windows) | |
|---|---|---|
| Включить | Cmd + F5 |
Ctrl + Alt + N |
| Следующий элемент | Ctrl + Option + → |
↓ |
| Следующий заголовок | Ctrl + Option + Cmd + H |
H |
| Список элементов (ротор) | Ctrl + Option + U |
Insert + F7 |
| Активировать | Ctrl + Option + Space |
Enter |
Задавайте себе вопросы: у каждого элемента понятное имя? Объявляются ли изменения (ошибки, добавление в корзину)? Понятно ли, где я нахожусь?
- Режимы отображения. Включите
prefers-reduced-motion,forced-colorsи тёмную тему через эмуляцию в DevTools (Rendering).
Тестируйте с людьми
Ни один чеклист не заменит пользователя, который каждый день работает со скринридером или голосовым управлением. Если продукт важный — включите таких людей в юзабилити-тестирование.
Чеклист перед релизом
Структура и семантика
-
<html lang="...">указан, фрагменты на другом языке размечены - Уникальный
<title>на каждой странице - Ориентиры:
header,nav(подписаны, если их несколько),main(один),footer - Заголовки отражают структуру, уровни не пропущены
- Кнопки —
<button>, ссылки —<a href>; нет кликабельныхdiv
Изображения и медиа
- У информативных изображений осмысленный
alt, у декоративных —alt="" - У кнопок и ссылок с иконками есть доступное имя
- У видео есть субтитры, у аудио — расшифровка; нет автовоспроизведения со звуком
Формы
- У каждого поля видимая
<label>, связанная с полем - Группы радиокнопок и флажков — в
fieldset+legend -
autocompleteу полей с личными данными - Ошибки: текстом рядом с полем,
aria-invalid,aria-describedby, фокус на первую ошибку - Вставка в поля пароля и кода разрешена
Клавиатура и фокус
- Весь сценарий проходится клавиатурой, ловушек нет
- Фокус всегда видим и контрастен; нет
outline: noneбез замены - Есть ссылка «Перейти к содержимому»
- Липкие элементы не перекрывают фокус (
scroll-padding-top) - Модальные окна: фокус внутри,
Escзакрывает, фокус возвращается - Нет
tabindexбольше 0
Визуальное
- Контраст текста ≥ 4,5 : 1 (крупного ≥ 3 : 1), компонентов и фокуса ≥ 3 : 1
- Информация не передаётся только цветом
- Страница читается при 320 px ширины и масштабе 200–400%
- Масштабирование не запрещено в
meta viewport - Учтены
prefers-reduced-motionиforced-colors - Цели нажатия ≥ 24×24 px (лучше 44×44 на мобильных)
Динамика
- Важные изменения объявляются через live-регион, существующий заранее
- При смене маршрута в SPA обновляется
titleи переводится фокус - Состояния ARIA (
aria-expanded,aria-pressed...) синхронны с интерфейсом
Проверка
- Линтер
jsx-a11yбез ошибок - axe (в тестах или расширении) без нарушений
- Ключевые сценарии пройдены клавиатурой и хотя бы одним скринридером
Источники и что читать дальше
Стандарты и справочники
- WCAG 2.2 и WCAG Quick Reference — W3C
- ARIA Authoring Practices Guide — паттерны виджетов и клавиатурные модели
- Using ARIA — правила применения ARIA
- MDN: Доступность — справочник по HTML, ARIA и практикам
- web.dev: Learn Accessibility — бесплатный курс от Google
Исследования и данные
- WebAIM Million 2026 — ежегодный анализ миллиона сайтов
- WebAIM Screen Reader User Survey — как на самом деле пользуются скринридерами
- Deque: Automated Testing Coverage
- ВОЗ: Инвалидность и здоровье
Практика и блоги
- WebAIM Articles — подробные статьи по каждой теме
- The A11Y Project — чеклист и статьи сообщества
- Adrian Roselli — глубокие разборы паттернов и их поддержки
- Sara Soueidan — доступный дизайн и вёрстка, SVG
- Scott O'Hara — нативные элементы и ARIA
- GOV.UK Design System — компоненты, проверенные на реальных пользователях
- Microsoft Inclusive Design
Инструменты
- axe-core и @axe-core/playwright
- eslint-plugin-jsx-a11y
- jest-axe
- WAVE и WebAIM Contrast Checker
- NVDA — бесплатный скринридер для Windows
Доступность — не отдельная фича и не финальный аудит, а привычка, такая же, как адаптивная вёрстка. Начните с малого: подписи к полям, видимый фокус, контраст и правильные кнопки закрывают большую часть того, на чём спотыкаются пользователи. Остальное приходит с практикой.
Серия «Доступный веб на практике»
- Доступность сайта: для кого она на самом деле и с чего начать
- Семантический HTML и альтернативный текст: фундамент доступного сайта
- Доступные формы: подписи, подсказки, ошибки и автозаполнение
- Клавиатура и фокус: как сделать сайт, которым можно пользоваться без мыши
- Контраст, анимация и размер кнопок: визуальная доступность сайта
- ARIA и динамический контент: когда атрибуты помогают, а когда вредят
- Доступность в React: id, фокус при смене маршрута и объявления
- Как тестировать доступность: автоматика, ручная проверка и чеклист — вы здесь
Agama Labs — разработка сайтов и веб-приложений. Если хотите проверить доступность своего сайта, напишите нам: hello@agamalabs.com


