Перейти к содержанию

Доступность интерфейса WebView

Карта возможностей помогает выбрать native или обычное действие. Теперь рассмотрим человека, который пользуется клавиатурой, увеличенным текстом или screen reader. Результат урока — договор доступного WebView, полный небольшой модуль переключения секций и предметные сценарии для формы учебного плана. Это подготовка интерфейса; реальное соответствие стандарту и работа конкретного клиента не объявляются подтверждёнными без выполнения.

Небольшая область экрана не оправдывает отсутствие подписей. Карточка курса имеет понятный заголовок и ссылку либо кнопку по назначению. Поля формы имеют label, а сообщение о результате отличает сохранение от неизвестного итога. Native MainButton находится вне DOM нашей страницы, поэтому её доступность зависит и от хоста. Если выбранная комбинация клиента и вспомогательных технологий не позволяет выполнить действие, обычный доступный вариант должен оставаться доступен по согласованному правилу, а не исчезать только из-за nativeCommit true.

Семантика до оформления

Ссылка переводит к адресу, button выполняет действие, select выбирает известный курс. Замена всех элементов на div с click требует вручную восстановить клавиатуру, роль, фокус и состояние. Для нашей формы нет причины брать эту ответственность. Привязанные label и aria-describedby из урока двенадцать объясняют поля до ошибки. При ошибке используется aria-invalid и конкретный текст; цветовая рамка может дополнить сообщение, но не заменить его.

Заголовки отражают структуру экрана, а не выбранный размер шрифта. Название приложения находится на верхнем уровне, экран курса получает следующий логичный заголовок. WAI о заголовках помогает сопоставить визуальную и программную структуру. Не пропускайте уровни только потому, что CSS h4 выглядит компактнее. Размер и отступ можно изменить стилем, сохранив смысл элемента.

Переключение секций

Навигация из урока семь передаёт render новый route. Теперь зададим минимальную ответственность представления: скрыть прежнюю секцию, открыть следующую и перевести фокус к выбранному началу. Полный panels.js работает с переданными DOM-элементами. Он не выбирает route и не сбрасывает draft, поэтому внешний callback может сохранить независимую модель плана.

export function switchPanel({previous, next, focusTarget}) {
  if (!(next instanceof HTMLElement) || !(focusTarget instanceof HTMLElement) ||
      !next.contains(focusTarget)) throw new Error('Panel contract mismatch');
  if (previous && previous !== next) previous.hidden = true;
  next.hidden = false;
  if (!focusTarget.hasAttribute('tabindex') &&
      !focusTarget.matches('button, a[href], input, select, textarea')) {
    focusTarget.setAttribute('tabindex', '-1');
  }
  focusTarget.focus();
}

Для входа в экран курса focusTarget может быть его заголовком; для возврата — кнопкой того курса, с которого был переход. Выбор относится к сценарию, не к универсальному правилу «всегда ставим фокус на первое поле». Hidden исключает прежнюю секцию из обычного отображения и взаимодействия; opacity: 0 этого не обеспечивает. Стили приложения не должны переопределять hidden так, чтобы невидимые поля продолжали попадать в Tab.

Модуль не является готовой полной системой фокуса: не все интерактивные HTML-элементы входят в его короткий selector. В нашем домене focusTarget — заголовок или обычная кнопка, поэтому выбранной ветки достаточно. При расширении custom elements и сложными контролами потребуется отдельный договор. Он также не создаёт focus trap: обычный экран не модальный dialog и не должен удерживать клавиатуру в нескольких элементах без способа выйти.

Сообщение после отправки

Form-message с role status сообщает начало ожидания и итог, но не повторяет каждую введённую цифру. Важная ошибка поля связана с самим полем. После submit с ошибкой контроллер ставит фокус на первый неверный ввод; общая область сообщает, что действие не выполнено. WAI о сообщениях формы объясняет связь сообщения, контекста и исправления. Для нашего плана это позволяет человеку сначала понять причину, затем сохранить исправленный выбор.

Не делайте интерфейс шумным. Если на каждый render повторно записывать одну и ту же строку в live region, screen reader может получать лишние объявления при изменении viewport и темы. Сообщение обновляется при переходе состояния операции, а не любой перерисовке. При write_unconfirmed важна короткая фраза о неподтверждённом итоге и конкретное доступное действие сверки; общий красный значок без текста не объясняет, сохранился ли draft.

Размер и пространство

У пальца должна быть понятная цель. Для собственного оформления мы выбираем удобные действия высотой около сорока восьми CSS-пикселей с промежутками. Это решение дизайна не следует называть точной нормой WCAG AA. В WCAG 2.2 критерий минимального размера 2.5.8 относится к двадцати четырём CSS-пикселям и оговорённым исключениям; более крупные цели могут быть полезны и сверх минимального требования.

Кнопки не перекрывают поле после открытия клавиатуры. Текст не обрезается фиксированной высотой карточки при увеличении шрифта. Safe areas из урока пять помогают рамке хоста, однако не доказывают, что focused input действительно виден в конкретном WebView. Ожидаемый сценарий включает увеличение текста, прокрутку к ошибке и возврат к каталогу. Для него нужно смотреть на реальный документ и клиент, а не только на размеры в CSS.

Тема и контраст

ThemeParams содержат цвета хоста, но их использование само по себе не подтверждает контраст каждой нашей комбинации. Например, hint_color может подходить вторичному тексту, но не важной ошибке на выбранном фоне. В собственной палитре нужно измерить фактические пары светлой и тёмной темы. Мы не записываем результат «WCAG проходит», потому что измерения здесь не выполнялись. Границы формы и focus outline должны оставаться различимыми при обоих оформлениях.

Доступное состояние не передаётся только зелёным или красным. «Сохранён план, версия пять» и «Итог пока не подтверждён» различаются текстом. Выбранный курс обозначается семантикой select, а не одной изменённой тенью карточки. Если добавится анимация, следует учитывать prefers-reduced-motion и не делать её обязательной для понимания результата. Наш базовый каталог вообще не нуждается в сложном движении, поэтому быстрый спокойный интерфейс проще сохранить доступным.

Предметный сценарий

Начните в обычном браузере: Tab должен дойти до select и действия, Enter — отправить форму через тот же контроллер, неверная частота — получить текст и фокус поля. Затем ожидается возврат из деталей к исходному курсу без фокуса в скрытой секции. После этого повторяется сценарий в выбранных клиентах Telegram, включая native действия и экранную клавиатуру. Разница окружений фиксируется в матрице, а не объявляется автоматически устранённой SDK.

Эти действия, screen reader, фокус, контраст и JavaScript здесь не запускались. Модуль переключения представляет точный фрагмент собственной реализации, а контракт отмечает будущую интеграцию render. Доступность является свойством полного потока, поэтому одна label или крупная кнопка не доказывает её целиком. В последнем уроке соберём материалы, незавершённые серверные границы и план выпуска учебного mini app в один честный реестр.

Оглавление серии