1. О чём эта статья
Уже более 10 лет мы сопровождаем Единый официальный сайт органов власти Ханты-Мансийского автономного округа — Югры (admhmao.ru, далее – сайт), в структуру которого входят ещё 36 сайтов органов власти округа. За это время требования к доступности государственных сайтов несколько раз менялись.
В этой статье мы рассказываем, как выполняли требования законодательства о доступности сайта для инвалидов по зрению, хотя между собой называем это просто «доступностью»: читать мелкий серый текст на белом фоне не любит никто. Покажем на реальном госпроекте, какие грабли ждут команду, когда большой legacy-сайт приводят к современным требованиям доступности. Большинство рекомендаций пригодятся при разработке любого сайта, не только государственного.
Актуальные требования к доступности изложены в Постановлении Правительства Российской Федерации от 07.02.2026 № 102 (здесь можно с ними ознакомиться).
Если коротко, вот с какими типовыми проблемами мы столкнулись — по ним можно быстро определить, «что не стоит делать» на подобном сайте:
· горизонтальная прокрутка при масштабировании до 200 %, прежде всего из-за широких таблиц;
· элементы, недоступные или невидимые при навигации с клавиатуры;
· role="tab" на обычных ссылках меню;
· отсутствие программной отметки текущей страницы (aria-current);
· кнопки-иконки без текстовых меток;
· PDF-просмотрщик с интерфейсом на английском языке;
· динамический контент, о появлении которого пользователь скринридера не узнаёт (фреймы, блоки «Посмотреть все»);
· виджет календаря, в котором нельзя выбрать день;
· изображения без атрибута alt;
· слайдеры с автопереключением;
· недостаточная контрастность текста;
· CAPTCHA без аудиоверсии на русском языке.
Дальше — подробно о каждой проблеме и о том, как мы её решали (или почему пока не решили).
2. Технологии и инструменты
Сайт работает на платформе Bitrix Framework, бэкенд написан на PHP. Фронтенд: HTML5, CSS3, JavaScript (jQuery и Vue.js).
Для проверки доступности мы использовали:
· NVDA — бесплатная программа экранного доступа (скринридер);
· Lighthouse — автоматический аудит в Chrome DevTools;
· Colour Contrast Analyser — проверка цветового контраста;
· axe DevTools — автоматическая проверка доступности страниц.
3. Как менялись требования
3.1. Ранние требования: отдельная версия для слабовидящих
Ранние требования (Приказ Министерства связи и массовых коммуникаций Российской Федерации от 30.11.2015 № 483, текст документа) обязывали предусмотреть на сайте отдельную версию для слабовидящих, если основная версия сайта требованиям приказа не удовлетворяла. Основные требования к такой версии:
· нетекстовая информация и нетекстовые материалы должны быть описаны в текстовом виде;
· графические файлы формата PDF, содержащие документы в графическом виде, должны быть представлены в текстовом виде;
· посетитель должен иметь возможность увеличить размер текста до 200 %, увеличить интервал между буквами, изменить шрифт и цветовую схему.
У версии для слабовидящих, существовавшей на сайте, были свои слабые места:
· скудный выбор цветовых схем — всего две, тогда как на образцовых сайтах встречалось до пяти;
· отсутствие встроенной озвучки текста.

3.2. Актуальные требования: доступной должна быть основная версия
В 2024 году подход радикально изменился: требования доступности теперь предъявляются к основной версии сайта, а отдельная версия для слабовидящих «отменяется» (Приказ Минцифры России от 07.11.2023 № 953, текст документа, вступил в силу 01.09.2024, утратил силу 01.03.2026 на основании приказа Минцифры России от 09.12.2025 № 1160; многие его требования в более проработанном виде «перекочевали» в актуальное Постановление Правительства Российской Федерации от 07.02.2026 № 102).
Сайт в целом должен быть удобен для всех: для слабовидящего пользователя, для человека с мобильным устройством, для того, у кого просто не оказалось под рукой мыши.
Нам повезло: незадолго до вступления в силу новых требований начался редизайн сайта, включая изменение структуры разделов, и к моменту вёрстки новых шаблонов мы уже знали о грядущих изменениях — новые требования доступности закладывали сразу в шаблоны, а не «прикручивали» задним числом.
4. Круглый стол: как мы разбирались в требованиях
Вплотную с новыми требованиями мы познакомились на круглом столе «Доступность интернет-ресурсов для особенных людей» в рамках XV Международного IT-Форума (июнь 2024 года, Ханты-Мансийск, запись мероприятия). Коллеги из других регионов, выступавшие с докладами, в дальнейшем не раз помогали нам расшифровывать нюансы требований при посредничестве кураторов сайта из Департамента информационных технологий и цифрового развития Югры. Они же помогли организовать проверку сайта незрячими тестировщиками (новость об этом).
5. Никакой горизонтальной прокрутки
Самая большая проблема нашего legacy-сайта была связана с требованием:
«текстовая информация, размещаемая на официальных сайтах, масштабируется не менее чем на 200 процентов исходного масштаба интернет-страницы без применения вспомогательных технологий, потери функциональности и появления горизонтальной полосы прокрутки».
Коллеги из других регионов в ходе консультации по требованиям нормативки акцентировали внимание на том, что по этой трактовке не допускаются никакие страницы с горизонтальной прокруткой, в том числе в исходном масштабе и в том числе страницы с таблицами.
На сайте с момента его разработки были разделы со статичными таблицами, например, вкладка «Документы» на главной. При увеличении масштаба до 200 % и на мобильных устройствах они неизбежно давали горизонтальную прокрутку.

Мы переработали таблицы в адаптивные: на широких экранах это обычная таблица, а на узких — строки превращаются в компактные карточки.


6. Работа только с клавиатуры
Много времени ушло на ручное тестирование работы сайта только с клавиатуры. Клавиатурная навигация важна не только для пользователей скринридеров, но и для тех, кто временно не может пользоваться мышью.
При тестировании возникали в основном две проблемы:
· на элемент нельзя навести фокус;
· фокус на элемент наводится, но визуально никак не выделяется (нет обводки).
Особое внимание уделяли «важным страницам»: главной и сервисам — телефонному справочнику и обращениям граждан, включая формы отправки обращений.
Самой тяжелой задачей при соблюдении требования стало обеспечение корректного скрытия и раскрытия меню третьего уровня с клавиатуры на главной странице и подсайтах. Первичный вариант решения пришлось откатить: при проверке в NVDA он давал новые ошибки. После долгих размышлений и ряда неудачных вариантов реализации пришлось полностью переработать меню.

7. Что нашли незрячие тестировщики
Сайт мы тестировали скринридером NVDA — он популярен среди людей с нарушениями зрения. Скринридер опирается в том числе на атрибуты элементов: прочитает alt у изображения, title у ссылки, aria-label у кнопки.
В 2026 году к тестированию удалось подключить незрячих тестировщиков — их проверка оказалась особенно ценной и выявила проблемы, которые мы сами не заметили. В работе они использовали скринридер и инструменты автоматической оценки доступности — Lighthouse и axe DevTools. Ниже — часть найденных проблем.
7.1. Вкладки, которые на самом деле ссылки
Ссылки в выпадающем главном меню были размечены атрибутом role="tab". Такая роль обещает пользователю переключение контента без перезагрузки страницы, но по факту происходил переход на другую страницу.

Код элемента «О Департаменте» до и после исправления
До исправления:
<ul class="nav-list-2-lvl flex-column align-items-start" id="pills-tab" role="tablist"> <li> <a class="hm__menu-button px-0 mb-1 lh-sm" role="tab" href="/about/rukovodstvo/">О Департаменте</a> </li> </ul>
После исправления — убрали role="tablist" у <ul> и role="tab" у всех <a>:
<ul class="nav-list-2-lvl flex-column align-items-start! position-relative"> <li class="d-flex align-items-start dropend"> <a class="hm__menu-button px-0 mb-1 lh-sm" href="/about/rukovodstvo/">О Департаменте</a> </li> </ul>
В результате ссылки снова стали ссылками — скринридер объявляет их корректно.
7.2. Скринридер не знает, на какой вы странице
При навигации по меню пользователи скринридеров не получали информацию о том, какой пункт соответствует открытой сейчас странице: текущий пункт выделялся только CSS-классом is-active, который ассистивным технологиям ничего не сообщает.
Решение — атрибут aria-current="page" на ссылке, ведущей на текущую страницу.
Код до и после исправления
До исправления:
<ul class="nav-list-2-lvl flex-column align-items-start" id="pills-tab" role="tablist"> <li class="is-active"> <a class="hm__menu-button px-0 mb-1 lh-sm" role="tab" href="/about/rukovodstvo/">О Департаменте</a> </li> </ul>
После исправления:
<ul class="nav-list-2-lvl flex-column align-items-start! position-relative"> <li class="d-flex align-items-start dropend"> <a class="hm__menu-button px-0 mb-1 lh-sm" href="/about/rukovodstvo/" aria-current="page">О Департаменте</a> </li> </ul>
7.3. Кнопки-иконки без имён
У части функциональной кликабельной графики отсутствовали текстовые метки — скринридеру нечего было объявить.

Решение — дать каждой интерактивной иконке aria-label с понятным описанием действия: «Закрыть поиск», «Найти поручения», «Выбрать район Лангепас».
Код кнопки поиска до и после исправления
До исправления:
<button class="btn text-muted ms-4 search" id="iconSearchMain"> <img class="pe-2" src="/local/templates/hmao/img/hm_magnifying-glass.svg" alt="Поиск"> </button>
После исправления (иконка стала инлайновым SVG, имя кнопки задаёт aria-label; декоративный SVG скрыт от ассистивных технологий):
<button class="btn text-muted ms-4 search" id="iconSearchMain" data-bs-toggle="collapse" data-bs-target="#collapseSearch" aria-expanded="false" aria-label="Поиск"> <svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"> <path d="M11 19.5C15.4183 19.5 19 15.9183 19 11.5C19 7.08172 15.4183 3.5 11 3.5C6.58172 3.5 3 7.08172 3 11.5C3 15.9183 6.58172 19.5 11 19.5Z" stroke="#818181" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path> <path d="M21 21.5L16.65 17.15" stroke="#818181" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path> </svg> </button>
Отметим: в исходном варианте у <img> был alt="Поиск", поэтому конкретно эта кнопка имя имела. Проблема касалась графических кнопок без alt и без aria-label — единый подход с aria-label на кнопке надёжнее и не зависит от способа вставки иконки.
7.4. PDF-просмотрщик говорил по-английски
Кнопки управления встроенного PDF-просмотрщика ViewerJS были подписаны на английском языке — неудобно для людей, не владеющих им, а скринридер и вовсе читал английские метки в русском интерфейсе.

Решение — локализовать метки кнопок: Presentation → «Презентация», Fullscreen → «На весь экран» и так далее.
Код кнопок верхней панели до и после локализации
До:
<div id="titlebarRight"> <button id="presentation" class="toolbarButton presentation" title="Presentation"></button> <button id="fullscreen" class="toolbarButton fullscreen" title="Fullscreen"></button> <button id="download" class="toolbarButton download" title="Download"></button> </div>
После:
<div id="titlebarRight"> <button id="presentation" class="toolbarButton presentation" title="Презентация"></button> <button id="fullscreen" class="toolbarButton fullscreen" title="Полноэкранный"></button> <button id="download" class="toolbarButton download" title="Скачать"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-download" viewBox="0 0 16 16" aria-hidden="true" focusable="false"> <path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5"></path> <path d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708z"></path> </svg> </button> </div>
Часть кнопок мы скрыли через CSS, чтобы разгрузить интерфейс просмотрщика:
.toolbarButton.fullscreen, .toolbarButton.presentation { display: none; }

7.5. Фокус не переносится на фреймы обратной связи
В блоке «Мой выбор, моё решение» при нажатии кнопок «Участвовать» и «Сообщить о проблеме» внизу страницы появляется фрейм с контентом, но пользователю скринридера об этом никто не сообщает.

Незрячие тестировщики порекомендовали реализовать автоматический перенос фокуса в появляющийся фрейм. На момент написания статьи мы всё ещё ищем работающее решение, но проблему важно упомянуть: это типичный случай, когда динамический контент «невидим» для пользователя скринридера.
7.6. «Посмотреть все» раскрывалось не туда
В блоке полезных ресурсов при нажатии кнопки «Посмотреть все» дополнительные ссылки появлялись в DOM выше кнопки. Пользователь, двигающийся по странице последовательно, просто не обнаруживал новый контент — он оставался «за спиной».

Незрячие тестировщики предложили компромиссный вариант: дописать в aria-label кнопки подсказку вида «раскрыть все ссылки (после активации кнопки нажимайте стрелку вверх)». Мы решили проблему иначе — исправили сам порядок элементов:
· блок со скрытыми ссылками перемещён ниже кнопки «Посмотреть все»;
· добавлена вторая кнопка «Скрыть все» — она размещена после блока ссылок и появляется при раскрытии;
· кнопка «Посмотреть все» при нажатии скрывается, но пользователь продолжает перемещаться по элементам с помощью клавиши Tab, фокус естественным образом перескакивает на первый элемент в раскрывшемся списке.
Так последовательность движения по странице сохраняется: раскрыл — двигаешься дальше вниз по новым ссылкам.

Код блока до и после исправления
До исправления:
<div class="tab-pane fade show active" id="pills-population" role="tabpanel" aria-labelledby="pills-population-tab"> <div class="row gy-3! service-container"> <!-- Основной блок со ссылками --> </div> <div id="showMore-population" class="row collapse"> <!-- Скрытый блок со ссылками: находится ВЫШЕ кнопки --> </div> <button class="accordion-button hm__collapse-button color-links hm__accordion-button! collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#showMore-population" aria-expanded="false" aria-controls="showMore-population" aria-label="Посмотреть все ссылки раздела «Гражданам»"> Посмотреть все </button> </div>
После исправления:
<div class="tab-pane fade show active" id="pills-population" role="tabpanel" aria-labelledby="pills-population-tab"> <div class="row gy-3! service-container"> <!-- Основной блок со ссылками --> </div> <button class="startService accordion-button collapsed hm__collapse-button color-links hm__accordion-button!" type="button" data-bs-toggle="collapse" data-bs-target="#showMore-population" aria-expanded="false" aria-controls="showMore-population" aria-label="Посмотреть все ссылки раздела «Гражданам»"> Посмотреть все </button> <div id="showMore-population" class="row collapse"> <!-- Скрытый блок со ссылками: теперь НИЖЕ кнопки --> </div> <button class="endService accordion-button collapsed hm__collapse-button color-links hm__accordion-button!" style="display:none" type="button" data-bs-toggle="collapse" data-bs-target="#showMore-population" aria-expanded="false" aria-controls="showMore-population" aria-label="Скрыть все ссылки раздела «Гражданам»"> Скрыть все </button> </div>
Обратите внимание на aria-label: его текст должен начинаться с видимого текста кнопки («Посмотреть все…»), иначе пользователи голосового управления не смогут активировать кнопку по её видимой надписи (критерий WCAG 2.5.3 Label in Name).
7.7. Календарь, в котором нельзя выбрать день
В виджете календаря пользователь скринридера мог перемещаться по годам и месяцам, но не мог выбрать конкретный день: NVDA не прочитывал числа месяца.

Код виджета (фрагмент)
<div class="ui-day-picker-month"> <div class="ui-day-picker-week --week-days"> <div class="ui-day-picker-week-day">Пн</div> <!-- Остальные дни недели --> </div> <div class="ui-day-picker-week"> <!-- Первая неделя месяца --> <button type="button" class="ui-day-picker-day" data-day="1" data-month="5" data-year="2026" data-tab-priority="true" role="gridcell" tabindex="0"> <span class="ui-day-picker-day-inner">1</span> <span class="ui-day-picker-day-marks"></span> </button> <!-- Остальные числа недели --> </div> <!-- Остальные недели месяца --> </div>
Это встроенный виджет календаря «Битрикса», поэтому вместо переписывания его на классическую доступную разметку (таблица <table> с навигацией по ячейкам) мы пошли по пути прагматичного упрощения: скрыли виджет от скринридера атрибутом aria-hidden="true" и оставили возможность ввести дату вручную с клавиатуры. Для поля добавили скрытую подпись — теперь при фокусе на поле скринридер сообщает: «введите дату поручения от, редактор, дд точка мм точка гггг».
Код интерфейса выбора даты после исправления
<div id="datePicker_DATE_FROM" class="hm__datePicker position-relative"> <span class="hm__wrap-calendar input-daterange pb-1 pb-sm-0 btn-group!"> <label class="visually-hidden" for="date_from"> Введите дату поручения от </label> <input type="text" id="date_from" class="hm__calendar form-control" name="date_from" value=""> <div id="DATE_FROM_BUTTON" class="hm__calendar-icon" aria-hidden="true"> </div> </span> </div>
Важный нюанс: aria-hidden="true" нельзя вешать на элемент, который остаётся доступным с клавиатуры, — скринридер «спотыкается» о фокусируемый, но скрытый элемент. Если кнопка открытия календаря фокусируема, ей дополнительно нужен tabindex="-1". В нашем случае кнопка календаря исключена из порядка табуляции, не доступна с клавиатуры.
7.8. Подписи к изображениям
Одно из ключевых требований доступности: вся нетекстовая информация должна быть представлена и в текстовом виде. Для изображений это означает обязательное заполнение атрибута alt — он должен описывать, что изображено.
Работа тут делится на двоих: разработчики дают контент-менеджерам возможность заполнить alt (и по возможности проверяют результат), а контент-менеджеры заполняют описания.
7.8.1. Автоматическая проверка
Раз в год мы запускаем по сайтам PHP-скрипт. Он выводит отчёт о страницах, где есть изображения без атрибута alt. Проверяем в основном новости и разделы, где департаменты создают страницы, — за последний год, т.к. страницы прошлых лет уже проверены в предыдущие итерации. По результатам формируем файл для каждого из 37 сайтов, и ответственные за сайты вручную добавляют недостающие описания.
PHP-скрипт проверки атрибута alt
// Ищем теги <img>, внутри которых нет атрибута alt $pattern_without_attr = "/<img((?!alt=)[^<>])+>/im"; // Типы инфоблоков, которые проверяем (здесь — новости) $arIblockTypes = Array( "news" => "news", ); // Проверяемые сайты: адрес и код сайта в Битриксе $arSites = array( "dh" => array( "PROPERTY_WWW_VALUE" => "https://depsport.admhmao.ru", "PROPERTY_SITE_ID_VALUE" => "dh", ), ); foreach ($arIblockTypes as $iblock_type) { foreach ($arSites as $site) { print_r($site["PROPERTY_WWW_VALUE"] . "\n"); print_r($site["PROPERTY_SITE_ID_VALUE"] . "\n"); print_wps_urls($site, $iblock_type); } } function print_wps_urls($site, $iblock_type) { CModule::IncludeModule("iblock"); $pattern = $GLOBALS["pattern_without_attr"]; $arSelect = Array("ID", "NAME", "DATE_CREATE", "DETAIL_PAGE_URL", "DETAIL_TEXT"); // Берём активные элементы, созданные с начала года. // DETAIL_TEXT — поле «Детальное описание», в нём хранится текст новости $arFilter = Array( "IBLOCK_SITE_ID" => $site["PROPERTY_SITE_ID_VALUE"], ">DATE_CREATE" => "01.01.2026", "ACTIVE_DATE" => "Y", "ACTIVE" => "Y", "IBLOCK_TYPE" => $iblock_type, "DETAIL_TEXT" => "%%", ); $res = CIBlockElement::GetList(Array(), $arFilter, false, false, $arSelect); while ($ob = $res->GetNextElement()) { $arFields_2 = $ob->GetFields(); preg_match_all($pattern, $arFields_2["DETAIL_TEXT"], $matches, PREG_SET_ORDER); if (empty($matches)) { continue; } // Выводим адрес и название проблемной страницы и сами теги без alt print_r("\nСсылка на элемент:\n"); print_r($site["PROPERTY_WWW_VALUE"] . $arFields_2['DETAIL_PAGE_URL'] . "\n"); print_r("Название элемента:\n"); print_r($arFields_2["NAME"] . "\n"); foreach ($matches as $match) { print_r($match[0] . "\n"); } } }
Запускаем скрипт в модуле «Командная PHP-строка» «Битрикса».

Пример вывода:
https://depsport.admhmao.ru dh Ссылка на элемент: https://depsport.admhmao.ru/news/6470065/ Название элемента: 25 ноября в Ханты-Мансийске стартует первый этап Кубка России по биатлону <img width="980" src="https://www.csp-ugra.ru/upload/poslednie_s_06.09.12/DSC_020202027.jpg" height="651"> <img width="980" src="https://www.csp-ugra.ru/upload/poslednie_s_06.09.12/DSC_00%D1%861270.jpg" height="651"> <img width="980" src="https://www.csp-ugra.ru/upload/poslednie_s_06.09.12/DSC_0056.jpg" height="651">
7.8.2. Помощь контент-менеджерам
Чтобы alt заполнялся уже на этапе создания новости, в админке рядом с каждым загружаемым изображением есть текстовое поле для описания — оно и выводится в атрибуте alt. Если контент-менеджер описание не заполнил или подвязал к новости фотогалерею, система подставляет подпись по шаблону — номер изображения и название новости:
<img class="hm__image f-lazyload is-lazyloaded" alt="Фото 1 к новости «Северный мох в Китае: югорчане с успехом представляют свои товары на выставке»" src="/upload/resize_cache/iblock/8f3/.../a3ad3912_3e57_4c71_8644_8e7181cca328.jpg">

7.8.3. Известные ограничения проверки
Честно перечислим, что наш скрипт пока не умеет:
· Проверка качества описания. alt может быть заполнен бесполезно: «DCS00567.jpg» или просто «изображение». Скрипт такие случаи не ловит — в планах добавить проверку на подобные шаблоны, пока это остаётся на совести администраторов сайтов. Вручную мы проверяем в основном только главные страницы.
· Автоподписи по шаблону. Подпись вида «Фото 1 к новости …» формально заполняет alt, но содержание изображения не описывает — такие изображения скрипт тоже не отслеживает. В планах на будущее реализовать автоматическую генерацию описаний изображений через ИИ.
7.9. Цель ссылки
Требование:
«цель каждой ссылки, размещаемой на официальных сайтах, определяется из текста ссылки или из текста ссылки вместе с её контекстом, который может быть распознан программным обеспечением».
Раз в год мы проверяем ссылки в текстах страниц на наличие атрибута title — тем же скриптом, что и изображения, только с другим регулярным выражением.
При этом мы понимаем ограничения такого подхода. В современной практике доступности:
· title считается слабым решением — скринридеры читают его непоследовательно, а на сенсорных устройствах он недоступен вовсе;
· предпочтительнее осмысленный текст самой ссылки или aria-label;
· наличие title само по себе не гарантирует, что цель ссылки понятна: формально требование — про текст ссылки и её контекст, а не про конкретный атрибут.
7.10. Осторожнее со слайдерами
В старой версии сайта на главной странице был слайдер новостей с автопереключением. По современным требованиям доступности движущийся и автоматически обновляемый контент должен иметь средства управления — возможность приостановить или отключить автопереключение.
При разработке новой версии сайта мы решили не усложнять и отказались от слайдеров полностью: вместо слайдера новостей статично отображается одна главная новость, которую задаёт администратор через административную часть.
7.11. Контрастность
Требование доступности: коэффициент контрастности текста по отношению к фону — не менее 4,5:1.
В текущем году после повторной проверки мы внесли небольшие правки в цвета шрифтов. Проверяли онлайн-инструментом Adobe Color Contrast Analyzer (подобных сервисов много). Нашли несоответствие в контрастности даты новости на главной странице сайта — там фон блока темнее, чем на сайтах исполнительных органов власти. После правки контрастность этого элемента составила 4,51:1.

7.12. Русская CAPTCHA
Если на сайте есть CAPTCHA, по требованиям доступности у неё должна быть аудиоверсия: пользователь может не вводить текст с изображения, а прослушать запись, где сквозь шум диктуются цифры. Второе требование — CAPTCHA должна быть на русском языке, и это касается как текстовой, так и аудиоверсии.
Мы несколько лет используем Yandex SmartCaptcha — в ней есть опция аудиокапчи на русском языке, что закрывает оба требования.
8. Итоги
8.1. Сводная таблица изменений
Проблема | Как было | Как исправили |
Работа с клавиатуры | Невозможно навести фокус на элемент | Focus management, стилизация фокуса |
Таблицы | Горизонтальный скролл | Адаптивные карточки |
Меню | role="tab" на ссылках | Семантическая навигация |
Текущая страница | Только class="is-active" | aria-current="page" |
Слайдер | Автопереключение | Убрали полностью |
Кнопки-иконки | Нет текстовых меток | aria-label |
PDF-просмотрщик | Кнопки на английском | Локализован на русский |
Фреймы обратной связи | Фокус не переносится на фрейм | Не решено |
Блок «Посмотреть все» | Новые элементы появлялись над кнопкой | Блок перемещён ниже кнопки, порядок движения по странице сохранён |
Виджет календаря | Недоступен для скринридера | Виджет скрыт (aria-hidden="true"), оставлен ручной ввод даты с подписью поля |
Контрастность | Коэффициент ниже 4,5:1 | Минимальный коэффициент — 4,51:1 |
8.2. Что нашли автоматические проверки, а что — люди
Почти всё тестирование доступности мы делали вручную, включая проверки незрячими тестировщиками. Автоматизировали только две вещи: поиск изображений без описаний и ссылок без заданного контекста на внутренних страницах.
8.3. Рекомендации другим командам
· Обращайтесь к людям с опытом адаптации сайтов. Самостоятельно понять все нюансы требований сложно, а цена неверной трактовки — переделки.
· Закладывайте доступность с самого начала. Разрабатывайте дизайн-макеты с учётом требований, чтобы потом не переделывать вёрстку.
· Помните: доступность — задача не только разработчиков. Контент-менеджеры, наполняющие сайт, влияют на неё не меньше.
· Закладывайте время. Доступность — это системная работа, особенно на больших legacy-проектах.
· Привлекайте к тестированию пользователей с нарушениями зрения. Никто не расскажет о проблемах доступности сайта лучше, чем люди, которые пользуются им через скринридер каждый день.
