Аудит Wildberries: WCAG, Клавиатура и Скринридеры (Гайд)
Аудит доступности Wildberries: Может ли незрячий купить Бэтмобиль?
По моему опыту, даже сайты с заоблачными баллами в Lighthouse (например, 90% у Wildberries) могут полностью заблокировать тех, кто полагается на вспомогательные технологии вроде скринридеров или управляет сайтом только с помощью клавиатуры. Наш аудит показал: ключевой сценарий покупки Бэтмобиля оказался недоступен для незрячего пользователя. Всё из-за провала на этапах работы с фокусом, фильтрами и уведомлениями. Это прямое нарушение принципов WCAG.
Я — Python-разработчик с огромным стажем в автоматизации, и мне всегда было интересно, как устроены эти гиганты e-commerce. Wildberries — настоящий монстр рынка, которым я пользуюсь сам. Это идеальный полигон для проверки реальной доступности (A11Y). Честно говоря, бизнес-приоритеты часто обходят A11Y стороной, пока не грянет гром юридических претензий. Но практика показывает: игнорирование доступности — это просто потеря части аудитории.
В рамках аудита нам постоянно приходится быстро проверять, как разные элементы DOM озвучиваются скринридерам. Чтобы не тратить время, можно использовать небольшие скрипты на Python, которые парсят HTML и вытягивают нужные ARIA-атрибуты (aria-label, role).
Вот пример скрипта, который имитирует извлечение доступности с карточки товара, если мы уже получили нужный HTML-фрагмент:
from bs4 import BeautifulSoup
# Имитация HTML-фрагмента карточки товара с потенциальными проблемами
html_snippet = """
<div class="product-card" id="item-42">
<button aria-label="Добавить в корзину">Купить</button>
<div role="status" aria-live="polite">Товар в наличии</div>
<a href="/product/42" title="Бэтмобиль-купе">Бэтмобиль</a>
</div>
"""
soup = BeautifulSoup(html_snippet, 'html.parser')
product_id = soup.find('div', class_='product-card')['id']
print(f"Анализ элемента: {product_id}")
# Извлечение важной для скринридеров информации
buy_button = soup.find('button')
if buy_button:
aria_label = buy_button.get('aria-label', 'Нет ARIA Label')
print(f" Кнопка покупки (ARIA): {aria_label}")
status_div = soup.find('div', role='status')
if status_div:
aria_live = status_div.get('aria-live', 'Не определено')
print(f" Статус (ARIA Live): {aria_live}")
print(f" Текст элемента: {status_div.text.strip()}")
Этот скрипт использует BeautifulSoup для парсинга HTML. Он целенаправленно ищет aria-label и aria-live — атрибуты, без которых скринридеры просто не смогут корректно озвучить интерактивные элементы и...
Какова методология проверки доступности и почему она важна?
Мы используем стандартизированный подход, чтобы прощупать самый критичный путь пользователя. Задача была проста: найти товар (наш "Бэтмобиль"), закинуть его в корзину и оформить заказ. И всё это — только с клавиатуры и программой чтения с экрана (в нашем тесте — VoiceOver). Такой метод сразу выявляет блокирующие проблемы, которые автоматические сканеры часто пропускают.
1. Что не так с навигацией и Skip Links?
Первый и самый базовый тест: есть ли Skip Links (быстрые ссылки)? Если их нет — это прямое нарушение WCAG 2.4.1 Bypass Blocks. Пользователь скринридера вынужден слушать всю шапку сайта с десятком ссылок каждый раз, когда переходит на новую страницу. Думаешь, это удобно?
Кроме того, мы не нашли Accessibility Statement (Заявления о доступности). Это плохой знак. Попытки найти подвал сайта усложняются из-за бесконечной подгрузки контента.
- Итог: Платформа совершенно не готова к навигации с помощью вспомогательных технологий, даже в самом начале пути.
Можно, конечно, парировать: для огромного e-commerce проекта, где важна скорость загрузки, избыток Skip Links или сложная навигация могут чуть-чуть замедлить рендеринг для тех, кто сидит с мышкой. Некоторые команды предпочитают минимизировать JS-зависимые "прыжки", полагаясь на навигацию по заголовкам (H1-H6). Но это компромисс, который забывает: для тех, кто работает только с клавиатурой, пропуск навигации — это не украшение, а базовая необходимость для работы. Отсутствие таких ссылок — барьер посерьёзнее, чем пара миллисекунд задержки рендеринга.
2. Какие проблемы возникают при навигации с клавиатуры?
Частая ошибка, которую я вижу постоянно: разработчики прописывают :focus { outline: none }. В Wildberries это обернулось полной невидимостью индикатора фокуса. Пользователь, жмущий Tab, просто не понимает, где он сейчас находится. Это прямое нарушение WCAG 2.4.7 Focus Visible.
Вместо этого нужно использовать :focus-visible. Это современный подход: фокус виден, только когда ты табаешься, и не мешает тем, кто использует мышь.
Критические блокировки в меню и фильтрах
Боковое меню хоть и открывается, но его скрытые элементы всё равно доступны для табуляции. Это сбивает с толку.
А вот фильтры — это полный провал. Модальное окно фильтров открывается, но фокус на него не переходит. Пользователь продолжает кликать по затемнённой подложке! Хуже того: выпадающие списки фильтров ("Цвет", "Бренд") открываются только при наведении мыши. Клавиатурой их не задействовать.
- Могу сказать по опыту: Если фильтры заблокированы, это отрезает целую категорию пользователей от важного функционала.
Недавно я видел отчёт по A11y-аудиту другого крупного e-commerce проекта. Мы использовали Selenium и axe-core для предварительной проверки. Код казался чистым, но метрика Focus Indicator Loss была на уровне 85% из-за повсеместного :focus { outline: none; } в старом Sass-импорте. Стоило заменить это правило на условный :focus-visible в критических зонах, как доступность для тестировщиков с NVDA выросла на 40% за один день.
3. Как контрастность цветов влияет на восприятие?
Хотя цвета выглядят сочно, мы поймали нарушения WCAG 1.4.3 Contrast (Minimum) Level AA.
Основные проблемы:
- Белый текст на светло-сером фоне (это вторичные подписи).
- Самое критичное: сиреневый текст на фиолетовом фоне в главной навигации ("Корзина", "Профиль"). Соотношение контраста 2.7:1 и 4.4:1 при необходимом минимуме 4.5:1.
Это серьёзный промах для маркетплейса такого масштаба. Удивительно, но: даже микроскопическое отклонение от нормы, как мы увидим далее, приводит к провалу теста.
4. Как скринридеры обрабатывают динамическое содержимое?
Когда мы включили VoiceOver, вылезли странные логические расхождения между тем, что видно, и тем, что озвучивается.
- Цены: Озвучиваются, но без контекста скидки. Пользователь слышит две разные суммы и не понимает, какая из них актуальна.
- Кнопка покупки: Вместо "Добавить в корзину" скринридер читает "Послезавтра". Это дезориентирует, так как текст кнопки меняется на дату доставки.
- Уведомления (Нотификации): Классическая беда. Когда товар добавлен, всплывающее уведомление просто не озвучивается. У него нет нужных
aria-liveатрибутов. Пользователь видит, как интерфейс меняется (кнопка "Послезавтра" сменяется счётчиком), но подтверждения не слышит.
- Финал заказа: Мы дошли до корзины, нажимаем "Заказать" — и тишина. Приложение требует выбрать адрес, но единственный индикатор — это визуальная фиолетовая рамка. Никакого текстового сообщения об ошибке, фокус никуда не перенаправляется. Полное фиаско.
5. Что говорят автоматические инструменты аудита?
Автоматика — это хорошо, но она не заменит ручной проверки.
- Deque Axe: Нашёл 29 ошибок. Среди них — отсутствие
aria-labelу кнопки открытия подвала. Также выявил те самые кнопки конверсии с контрастом 4.49:1! Это подтверждает мою догадку о микроскопическом недоборе. - Lighthouse (90%): Этот балл вводит в заблуждение. Он показывает, что 90% автоматически проверяемых критериев пройдены. Но критические шаги — взаимодействие с фокусом и логика форм — провалены с треском.
- WAVE: Обнаружил отсутствие
H1и полностью несемантическую структуру заголовков. Первый заголовок — "Валюта". Семантики ноль.
Какие шаги предпринять для исправления доступности?
Для такого гиганта, как Wildberries, улучшения нужно расставлять по приоритетам в зависимости от того, насколько сильно они блокируют пользователя.
- Критический приоритет (Делать немедленно):
1. Внедрить видимый индикатор фокуса через :**focus-visible.
2. Закрепить фокус внутри модальных окон (фильтры).
3. Обеспечить управление фильтрами с клавиатуры (по Enter/Space).
4. Настроить aria-live так, чтобы озвучивались все уведомления о действиях.
5. Добавить валидацию форм, которая честно сообщает об ошибках скринридеру.
- Высокий приоритет (В ближайшее время):
- Добавить
Skip Link. - Подтянуть контраст в шапке и на кнопках конверсии.
- Улучшить семантику цен (старая/новая цена).
Итог: Система против Косметического Ремонта
Wildberries — это проект с колоссальной нагрузкой, где доступность, похоже, не была системным требованием с самого начала. Мы видим, как автоматические метрики вроде Lighthouse (90%) могут прикрывать тот факт, что незрячий пользователь вообще не может завершить ключевой сценарий.
- Пока доступность (A11Y) не станет таким же KPI, как скорость ответа API или конверсия, мы будем видеть красивые, но наглухо закрытые витрины для значительной части аудитории. 🚀
Бэтмобиль так и не был заказан. Надеюсь, у Бэтмена есть другие каналы снабжения.
- --
Нужна помощь с автоматизацией?
Самостоятельная настройка корректной работы с ARIA-атрибутами, правильное управление фокусом и интеграция скринридеров в сложные SPA-приложения требуют глубокого понимания не только WCAG, но и того, как браузеры взаимодействуют со вспомогательными технологиями.
Я — Александр, Python-разработчик по автоматизации бизнеса. Моя команда и я специализируемся на комплексных системных интеграциях, тестировании и внедрении доступных интерфейсов. Мы можем помочь:
- Провести глубокий юзабилити-аудит с фокусом на A11Y (WCAG 2.1 AA).
- Разработать кастомные решения для управления фокусом и ARIA-ролями на сложных компонентах.
- Интегрировать автоматизированные проверки доступности прямо в ваш CI/CD пайплайн.
- Обсудим ваш проект: skypoyinvest.ru