Сообщения о результате без перемещения фокуса
Форма из предыдущего урока показывает, почему поле не прошло проверку. При успехе текст появляется ниже кнопки, но фокус остаётся на месте. Визуальный читатель может заметить изменение, а при другом способе чтения оно не обязательно станет известным без перехода к новому абзацу. Для таких результатов существует программно определяемое сообщение состояния.
Продолжим прототип a11y-lab. Его действие по-прежнему ограничено клиентской проверкой учебного адреса; письма не отправляются. Добавим роль области результата и изменим текст так, чтобы повторная проверка представляла отдельное событие. Затем разберём, какие изменения стоит объявлять и почему переносить фокус на каждое сообщение неудобно.
Область существует до обновления
В lesson.html замените только существующий пустой абзац feedback-status. Он остаётся после кнопки внутри формы:
<p id="feedback-status" role="status" aria-atomic="true"></p>
Пустая область заранее присутствует в документе и получает текст после действия. role="status" задаёт подходящую семантику для сообщения, которое не должно перехватывать управление. У этой роли есть неявные свойства живой области; aria-atomic="true" явно показывает намерение воспринимать обновление целиком. Действие роли описано в MDN, status.
Сообщение не скрывается через hidden. Его обычный видимый текст нужен всем читателям, а роль сообщает дополнительный способ получить изменение. Не следует делать успех доступным только скринридеру, оставляя на экране непонятную смену значка. Одна и та же информация должна объяснять результат в каждом представлении.
Если создать новую область и сразу заполнить её в одном действии, поведение объявления может различаться. Постоянный контейнер с последующим изменением проще включить в модель интерфейса. Это не обещание одинакового времени озвучивания во всех программах: настройки и текущая работа читателя влияют на представление. Для будущей проверки потребуется наблюдать выбранное сочетание средств.
Повторная проверка — отдельный результат
В lesson.js замените целиком обработчик feedbackForm.addEventListener('submit', ...) из предыдущего урока следующей версией. Объявления переменных, showEmailError, clearEmailError и включение noValidate сохраняются. Старый обработчик не должен оставаться рядом, иначе одно действие выполнится дважды:
let feedbackAttempt = 0;
feedbackForm.addEventListener('submit', event => {
event.preventDefault();
feedbackAttempt += 1;
feedbackStatus.textContent = '';
let message = '';
if (feedbackEmail.validity.valueMissing) {
message = 'Введите электронную почту, например reader@example.com.';
} else if (feedbackEmail.validity.typeMismatch) {
message = 'Проверьте формат адреса: ожидается имя@домен.';
}
if (message) {
showEmailError(message);
feedbackEmail.focus();
return;
}
clearEmailError();
feedbackStatus.textContent = `Проверка ${feedbackAttempt}: ` +
'формат адреса принят. Ничего не отправлено.';
});
Номер попытки различает последовательные успешные действия с одним значением. Без изменения текста повторная запись той же строки не обязательно воспринимается как новое значимое обновление. Здесь мы не принуждаем технологию прерывать речь, а предоставляем новое содержательное сообщение. Для настоящего сервиса вместо номера может быть важен другой результат, например название обработанного объекта.
Сообщение не содержит сам адрес. Для учебной задачи достаточно сообщить результат формата и границу проверки. Повтор длинного значения увеличил бы объём объявления, не помогая понять следующее действие. Если в интерфейсе несколько параллельных операций, имя объекта может понадобиться, но его полезность следует оценить по контексту.
После успеха фокус остаётся на кнопке или другом месте, откуда была выполнена отправка. При ошибке он переходит к одному полю, как в прошлом уроке. Это разные модели обратной связи: исправление требует вернуться к определённому месту, а успешное завершение не обязательно требует перемещения. Роль состояния не должна сама становиться новой остановкой Tab.
Результат и изменение контекста
Критерий Status Messages рассматривает сообщения о результатах, ожидании и других предусмотренных состояниях, которые могут быть представлены без получения фокуса. Его задача не заключается в объявлении каждого изменения DOM. Раскрытие меню, переход на новую страницу и обновление результата требуют различать собственные модели взаимодействия.
Например, раскрытая навигация уже имеет кнопку с aria-expanded. Дополнительное сообщение «Меню открыто» в живой области может дублировать существующее состояние. Открытие диалога имеет собственную цель фокуса и контекст. Добавление role="status" ко всему диалогу не заменит его название и управление. Необходимое сообщение выбирается по задаче, а не по факту изменения HTML.
Успех учебной проверки — подходящий пример: рядом появился результат, но читатель продолжает работать в той же форме. В другом курсе сохранение офлайн-главы может дать сообщение «Глава сохранена», а прерванная загрузка — объяснение доступного продолжения. Эти варианты должны сообщать действительную границу результата. «Готово» при незавершённой операции не становится полезным от правильной роли.
Не каждое обновление требует прерывания
Для обычного результата подходит спокойная модель состояния. Срочное уведомление имеет другую семантику и может сильнее влиять на чтение. Не назначайте alert всем небольшим изменениям только ради гарантированной заметности. Если приложение озвучивает каждую букву ввода, каждый шаг прокрутки и каждое изменение счётчика, важная информация теряется в потоке.
В нашей форме ошибка уже связана с полем и после проверки получает фокус. Одновременное объявление той же ошибки отдельной срочной областью может создать повтор. В длинной форме может понадобиться сводка, однако тогда её место и связь с полями проектируются осознанно. Нельзя выбрать один глобальный механизм и без различий применить его к успеху, ошибке, меню и диалогу.
Для процесса с частыми обновлениями полезно определить существенные моменты: начало, завершение, возможность продолжить после сбоя. Отображение каждого процента не обязательно должно приводить к отдельному голосовому сообщению. Если процент действительно является управляемым показателем, ему требуется соответствующая модель, а не длинный абзац, меняющийся десятки раз в секунду. MDN разбирает живые области.
Наблюдение, которое потребуется получить
Будущий сценарий включает успешную проверку, повтор той же проверки и исправление ошибочного значения. В каждом случае наблюдайте отдельно текст на экране, положение фокуса и объявление результата. Если одна часть отсутствует, это конкретное различие, а не основание назвать весь интерфейс успешным или неуспешным без дальнейшего разбора.
Запишите также момент сообщения относительно текущего чтения. Спокойная живая область может ждать удобного момента; задержка не всегда означает отсутствие связи. Если объявление вообще не появилось, проверьте исходное существование контейнера, действительное изменение текста и свойства элемента. Точная версия браузера и вспомогательной технологии поможет повторить наблюдение.
Теперь у формы есть названия, связанные ошибки и отдельное представление успешного результата. Основное состояние стенда готово для последовательного чтения со скринридером. Следующий урок соединит ранее созданные части в маршрут: название документа, области, оглавление, код, таблицу, форму и продолжение чтения.