Доступность мобильных приложений: VoiceOver, TalkBack и WCAG на практике
Приложение отклонили в App Store по гайдлайну 1.1, или пришёл запрос от корпоративного клиента с требованием WCAG 2.1 AA — обе ситуации означают одно: accessibility не был заложен в архитектуру с самого начала, а теперь его нужно встраивать в готовый продукт. Это больно.
Почему «добавить доступность потом» не работает
Самая частая проблема — разработчики воспринимают VoiceOver и TalkBack как косметику. Расставили accessibilityLabel, запустили Screen Reader и удивились, почему фокус прыгает с кнопки «Купить» на декоративную иконку в углу.
На iOS ошибка живёт в неправильной группировке элементов. Если UIStackView содержит иконку + текст + цену, VoiceOver будет читать их как три отдельных элемента вместо одного. Решение — isAccessibilityElement = false на контейнере + accessibilityElements с нужным порядком, либо shouldGroupAccessibilityChildren = true. Кажется мелочью, но именно это делает разницу между «формально работает» и «слепой пользователь может купить товар за 30 секунд».
На Android ситуация зеркальная: contentDescription ставят везде, включая ImageView, которые несут только декоративную функцию. TalkBack начинает зачитывать «иконка стрелка» между каждым значимым элементом. Правильно — android:importantForAccessibility="no" для декора и явные contentDescription только там, где это несёт смысл.
Dynamic Type и масштабирование шрифтов
iOS Dynamic Type ломает верстку предсказуемо: фиксированные высоты строк в UILabel, захардкоженные frame в Auto Layout, numberOfLines = 1 без adjustsFontSizeToFitWidth. Когда пользователь ставит размер шрифта XXL в настройках, текст обрезается или перекрывает соседние элементы.
Правильная реализация использует .font = UIFont.preferredFont(forTextStyle: .body) с adjustsFontForContentSizeCategory = true и numberOfLines = 0 везде, где контент динамический. В SwiftUI это работает из коробки через .dynamicTypeSize() modifier.
На стороне Flutter эквивалент — textScaleFactor через MediaQuery. Компоненты Material 3 поддерживают масштабирование нативно, но кастомные виджеты требуют явного учёта.
WCAG 2.1 в мобильном контексте
Мобильные приложения формально не обязаны следовать WCAG (он писался для веба), но WCAG 2.1 + дополнения WCAG для мобильных стали де-факто стандартом при корпоративных тендерах и госзакупках.
Критичные критерии применительно к мобилу:
- 1.4.3 Contrast Minimum — соотношение контраста текста к фону минимум 4.5:1. Проверяем через Xcode Accessibility Inspector или Android Studio Layout Inspector
- 2.4.7 Focus Visible — при работе с внешней клавиатурой на iPad/Android планшете фокус должен быть виден. Часто забытый сценарий
- 2.5.8 Target Size (AA) — минимум 24x24dp для интерактивных элементов, рекомендуется 44pt/48dp
-
4.1.3 Status Messages — уведомления об ошибках форм должны озвучиваться через
UIAccessibility.post(notification: .announcement)илиAccessibilityNodeInfo.RoleDescriptionна Android
Как строим процесс
Аудит начинается с Accessibility Inspector в Xcode и TalkBack developer settings на Android — проходим все экраны со Screen Reader включённым и фиксируем каждый случай, когда требуется более 3 действий для выполнения целевой операции.
Дальше — автоматизированные проверки. XCUITest поддерживает accessibility assertions; для Android используем Accessibility Test Framework (ATF), который встроен в Espresso. Это ловит регрессии на CI.
Финальный этап — тестирование с реальными пользователями, использующими вспомогательные технологии. Никакой автоматизацией это не заменить.
| Инструмент | Платформа | Что проверяет |
|---|---|---|
| Xcode Accessibility Inspector | iOS/macOS | Метки, контраст, порядок фокуса |
| Android Accessibility Scanner | Android | Контраст, размеры touch targets |
| Deque axe DevTools | Cross-platform | WCAG-соответствие |
| VoiceOver (iOS) | iOS | Навигация через Screen Reader |
| TalkBack (Android) | Android | Навигация через Screen Reader |
Сроки
Аудит и базовое исправление существующего приложения — от 2 до 5 недель в зависимости от числа экранов и глубины проблем. Внедрение accessibility с нуля в новый проект практически не влияет на сроки при правильном дизайне компонентной системы — закладываем 10-15% overhead на разработку UI-слоя.







