Всё про доступность интерфейсов
7 subscribers
116 photos
193 links
Download Telegram
Когда «следующее» сообщение оказывается предыдущим

В Expensify открыли issue про мобильный чат: с TalkBack включённым свайп к следующему элементу ведёт к предыдущему сообщению, а свайп назад - к следующему. То есть разговор читается в перевёрнутом порядке.

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

Причина завязана на список сообщений и порядок элементов в FlashList. Визуально такой чат может выглядеть нормально: новые сообщения снизу, прокрутка работает, кнопки на месте. Но для TalkBack и VoiceOver важен не внешний вид списка, а программный порядок фокуса и чтения.

Командам стоит проверять не только «можно ли дойти до сообщения», а как читается весь разговор. Откройте чат с несколькими сообщениями, включите TalkBack или VoiceOver и пройдите его обычными жестами вперёд-назад. Если «следующее» и «предыдущее» меняются местами, это уже сломанная последовательность, даже если интерфейс визуально кажется правильным.

Источник: Expensify/App#94165
Открытый список - ещё не закрытый сценарий

Свежий issue в Forui: FSelect открыт, пользователь идёт по вариантам через TalkBack, доходит до конца - и следующий свайп уводит фокус на поле под списком. Поповер при этом остаётся открытым.

Вывод для команд: у выпадающих списков, меню и поповеров нужно проверять не только названия пунктов, а границу слоя. Пока слой открыт, TalkBack/VoiceOver не должны тихо проваливаться на страницу за ним.

Источник
Открытый список - ещё не закрытый сценарий

В Forui завели свежий issue про FSelect в Flutter. Сигнал конкретный: пользователь открывает выпадающий список, идёт по вариантам через TalkBack, доходит до последнего пункта - и следующий свайп уводит фокус на поле под списком. Сам список при этом остаётся открытым.

Визуально это может выглядеть нормально: поповер открыт, варианты на экране, рядом есть затемнение или барьер. Но для пользователя с экранным доступом граница слоя не сработала. Он уже оказался на странице под открытым списком и не может спокойно понять, где сейчас находится и к какому состоянию относятся действия.

Интересная деталь: поведение зависит от геометрии. Более широкий список слева после последнего пункта попадает на барьер, а узкий список справа перескакивает к следующему полю. То есть порядок чтения определяется не рабочим сценарием, а расположением элементов на экране.

Мейнтейнер Forui ответил, что это упирается в ограничение Flutter OverlayPortal: один FocusScope удерживает клавиатурный фокус, но сам по себе не удерживает линейную навигацию TalkBack/VoiceOver. Для экранного доступа нужно отдельно проверять, что фоновые узлы убраны из дерева или слой действительно ведёт себя как отдельный маршрут.

Проверка для команд простая: откройте select, меню, поповер или похожий слой с включённым TalkBack/VoiceOver и пройдите его свайпами до конца. Фокус не должен тихо уходить на страницу под слоем. Если уходит - у вас сломан не “лейбл”, а граница сценария.
NVDA слышит «Data grid» - и на этом работа с субтитрами заканчивается

В Subtitle Edit v5.1.0-beta5 пользователь с NVDA описал редкий честный момент: часть доступности уже поправили, меню и многие подписи стали лучше. Но главный рабочий путь всё ещё ломается в месте, которое на вид может казаться обычной таблицей.

В окне горячих клавиш и других местах NVDA произносит только «Data grid». Дальше нельзя понять строки, выбранный пункт, текущую комбинацию клавиш или назначить новую. В обсуждении пользователь прямо пишет: из-за недоступной таблицы он не может даже проверить, какие клавиши отвечают за вставку субтитра и переход к полю редактирования.

Похожая проблема с выпадающими списками и числовыми полями: значение меняется визуально, но NVDA не произносит новое значение сразу. Для зрячего это мелкая шероховатость. Для человека с экранным доступом это состояние «я нажал стрелку, но не знаю, что выбрал».

Здесь проверка не заканчивается на «у кнопок есть имена». В редакторах, админках и любых сложных инструментах нужно пройти весь рабочий путь с экранным доступом: меню, таблицы, горячие клавиши, поля ввода, изменение значений и возврат фокуса. Если таблица говорит только свою роль, а не содержимое, пользователь не управляет интерфейсом - он угадывает его.
VoiceOver не видит выбранные рубрики в WordPress iOS

В свежем issue по WordPress для iOS пользователь описал простой, но неприятный сценарий: при создании записи он открывает настройки статьи, доходит до рубрик и выбирает, куда отнести текст. Визуально выбранная рубрика есть, но VoiceOver не говорит, выбрана она или нет.

То есть человек слышит названия вроде «uncategorized», «books», «movies», но не получает состояния: какая рубрика уже выбрана, а какая нет. Для зрячего пользователя это мелкая отметка в списке. Для пользователя VoiceOver это риск опубликовать материал не туда или долго перепроверять действие вслепую.

Автор issue отдельно пишет важную вещь: не надо просто дописывать слова selected / unselected в текстовые метки. Правильнее сделать элемент нормальным переключателем или чекбоксом, чтобы состояние отдавалось через доступность как состояние элемента, а не как костыль в названии.

Для команд вывод простой: в списках выбора мало проверить, что пункт читается. Нужно пройти весь путь с экранным доступом и проверить имя, роль, значение и состояние: выбран / не выбран, отмечен / не отмечен. Особенно там, где ошибка меняет результат публикации, заказа, платежа или настройки.

Источник: wordpress-mobile/WordPress-iOS#25737
Когда ошибка формы видна, но не слышна

Коротко: новый разбор issue → audit → PR по доступности интерфейса. Полный текст — следующим сообщением.
Когда ошибка формы видна, но не слышна

На этой неделе я выбрал Indico - систему для конференций и событий. Там нашёлся хороший пример не одной «кнопки без подписи», а связанной проблемы в общих интерфейсных паттернах.

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

Вторая часть - панели действий в списках. Кнопки вроде удаления, оценки или экспорта визуально отключены, пока ничего не выбрано. Но если такое состояние не отражено программно, клавиатура и скринридер могут всё равно приводить человека к нерабочим действиям.

Я сдела PR, который чинит это на уровне общих механизмов: ошибки связываются с полями через aria-invalid и aria-describedby, выпадающие меню получают состояние открытия, а действия, зависящие от выбранной строки, уходят из порядка Tab, пока они недоступны.

Это хороший тест для любой команды: проверять нужно не только «есть ли текст ошибки на экране», а слышит ли пользователь связь между полем, ошибкой и следующим действием.

Кейс подготовлен с помощью Accessibility Auditor Skill.

Issue #7624: формы и ошибки
Issue #7625: панели действий
PR: indico/indico#7637
Когда голосовая клавиатура перестаёт быть доступной

В issue по Dictate Keyboard попал отзыв незрячего пользователя из Google Play: после обновления приложение «больше не доступно» с TalkBack и ещё одной программой экранного доступа, название которой, похоже, исказилось при переводе.

Здесь важна не сама фраза «не хватает подписей». Dictate Keyboard - это клавиатура для диктовки текста. Если пользователь не может найти микрофон, выбрать язык, запустить запись, проверить результат или воспользоваться плавающей кнопкой, он теряет не украшение интерфейса, а способ ввода.

В самом issue перечислены вероятные места поломки: кнопки-иконки без contentDescription, кастомные строки в настройках без роли и семантики, новый Smartbar, плавающая кнопка, диалоги и оверлеи, где фокус TalkBack может теряться или застревать.

Для команды вывод простой: после переработки клавиатуры нельзя проверять доступность только на экране настроек. Нужно пройти весь путь с TalkBack: добавить язык, открыть клавиатуру в другом приложении, начать диктовку, остановить запись, прочитать результат, открыть подсказки и закрыть плавающие элементы.

Особенно у голосовых и AI-интерфейсов доступность держится на мелочах состояния. Кнопка должна быть видимой, называться, фокусироваться, говорить, что сейчас происходит, и не исчезать из маршрута экранного доступа после очередного «красивого» обновления.
Форма есть, но в неё нельзя попасть

В BlueBubbles для Windows открыли баг про стартовую настройку клиента. Пользователь с NVDA не может пройти форму подключения к серверу: поля адреса и пароля не попадают в обычный порядок Tab, а если найти их через объектную навигацию NVDA, текст всё равно не вводится.

Это неприятный тип поломки: интерфейс визуально показывает форму, но для незрячего пользователя она не становится рабочей формой. В итоге человек не просто тратит лишнее время на настройку. Он не может подключить клиент и начать пользоваться приложением вообще.

В обсуждении появился ещё один похожий сигнал: голосовая диктовка Wispr Flow тоже не может корректно найти поле ввода нового сообщения в BlueBubbles и вставить продиктованный текст. То есть проблема бьёт не только по экранному доступу, но и по связке «диктовка + поле ввода».

Для команд вывод простой: форму нельзя проверять только глазами и мышью. Минимальный тест для Windows - пройти первичную настройку с клавиатуры и NVDA: Tab до каждого поля, понятное имя поля, настоящий фокус, ввод текста, ошибка, повторная попытка. Если поле видно, но не принимает ввод через доступный фокус, это не форма, а картинка формы.

Источник: BlueBubblesApp/bluebubbles-app#2965
DBeaver: настройка «для NVDA» может сломать доступ к таблице

В открытом баге пользователь описывает странный сценарий: включаешь screen reader type = NVDA, открываешь View data - и редактор данных перестаёт быть доступным.

Фокус не попадает в таблицу, стрелки не работают, меню не вызывается. Проверять нужно не наличие «режима доступности», а весь рабочий путь после его включения.

Источник: dbeaver/dbeaver#39720
Когда настройка «для NVDA» ломает саму таблицу

В DBeaver открыт баг: пользователь с NVDA включает в настройках интерфейса режим screen reader type = NVDA, открывает таблицу через View data - и редактор данных перестаёт быть доступным.

По описанию, фокус не попадает в таблицу, стрелки не работают, контекстное меню не вызывается. То есть проблема не в том, что таблица «не очень удобно читается». Пользователь фактически не может обследовать данные и работать с ними через клавиатуру и экранный доступ.

Важно, что это происходит именно после включения настройки, которая должна помогать NVDA. Автор повторно подтвердил воспроизведение на DBeaver 25.3.0 и позже написал, что проблема всё ещё актуальна на DBeaver 26.0.3 с NVDA 2025.3.3.

Для интерфейсов тут хороший урок: специальные режимы доступности нельзя считать автоматически полезными. Их нужно проверять как отдельный сценарий.

Если в продукте есть настройка «NVDA», «экранный диктор», «клавиатурный режим» или любой похожий флажок, тест должен быть очень приземлённым: включили настройку, открыли реальную таблицу, прошли по ячейкам стрелками, вызвали меню, изменили фокус, вернулись назад.

Иначе может получиться неприятная ловушка: обычный режим ещё как-то работает, а режим, который пользователь включает ради доступности, отрезает ему основной рабочий экран.

Источник: dbeaver/dbeaver#39720
GOV.UK: число и подпись должны звучать как одна фраза

VoiceOver и TalkBack читают текстовый Big number как два отдельных элемента. Визуально это один показатель, на слух - обрывки контекста.
Когда число и подпись распадаются на два элемента

В GOV.UK Publishing Components завели свежий issue про компонент Big number. Визуально он показывает одну фразу: например, «82 Open consultations». Но VoiceOver на iOS/macOS и TalkBack на Android читают текстовую версию как два отдельных элемента: сначала «82», потом «Open consultations».

Для зрячего пользователя это один показатель. Для пользователя экранного доступа это уже два фрагмента интерфейса, между которыми нужно догадаться о связи. В аудите GOV.UK прямо описали риск: человек может услышать «66», затем «Open consultations» и решить, что это разные ссылки или разные элементы, а не одно значение с подписью.

Интересная деталь: для JAWS и NVDA команда уже нашла отдельное исправление в PR #5458, но для VoiceOver и TalkBack текстовая версия всё ещё ведёт себя иначе. То есть «починили для одного набора экранных читалок» не равно «компонент стал доступным везде».

Если интерфейс собирает смысл из нескольких визуальных кусков - число, подпись, суффикс, статус, единицы измерения, - его нужно проверять на слух как одну пользовательскую фразу. Не только по HTML и не только в одном экранном доступе.

Хороший тест простой: закрыть глаза, пройти компонент VoiceOver/TalkBack/NVDA/JAWS и спросить себя: я слышу цельную мысль или набор обрывков, связь между которыми надо восстанавливать самому?
Kibana: кнопка показывает значение, но VoiceOver не слышит состояние

Свежий кейс про простую кнопку «показать / скрыть»: важно озвучивать не только имя действия, но и состояние после нажатия.
Кнопка «показать значение» должна говорить, что она уже включена

В Kibana завели свежий баг по VoiceOver: на странице Synthetics → Settings кнопка View parameter value показывает или скрывает значение параметра, но экранный доступ в обоих состояниях произносит одно и то же: «View parameter value, button».

Зрячий пользователь видит, что значок глаза поменялся и значение стало видимым или снова скрытым. Пользователь с VoiceOver этого состояния не получает. Он нажал кнопку, а дальше должен угадывать: значение уже открыто, закрыто или действие вообще не сработало.

В настройках мониторинга это не абстрактная мелочь. Там могут быть параметры окружения, адреса, токены, рабочие значения для проверок. Если интерфейс не сообщает состояние, человек не может уверенно управлять даже простой операцией «показать / скрыть».

Хорошо, что по issue уже открыт PR: в кнопку добавляют aria-pressed, а подпись меняется между «View parameter value» и «Hide parameter value». Для такого действия мало иметь доступное имя кнопки - нужно озвучить состояние после нажатия.

Командам стоит отдельно проверять все такие переключатели: показать пароль, скрыть значение, включить фильтр, закрепить, заглушить, раскрыть блок. После активации экранный доступ должен сказать имя кнопки и новое состояние.

Источник: elastic/kibana#276962, связанный PR: #277162.
Меню видно, но экранный доступ его не открывает

В WordPress-теме Neve завели issue про выпадающее меню: пункт с подменю до него доходит, NVDA или TalkBack его озвучивает, но активация через экранный доступ может не раскрывать список. Мышью и обычной клавиатурой путь при этом выглядит рабочим.

По описанию, проблема не в одном пропущенном ярлыке. В desktop-варианте submenu control сделан как div role="button", обработчик клавиатуры слушает только Enter, click- и keyboard-состояния живут раздельно, а состояние раскрытия не отдано как aria-expanded. В итоге пользователь слышит контрол, нажимает его своим способом, но дочерние ссылки меню так и не становятся доступным маршрутом.

Это неприятный класс багов: интерфейс вроде бы «доступен», потому что элемент фокусируется и называется, но настоящая задача не выполняется. Для незрячего пользователя это значит простое: часть навигации сайта закрыта, хотя визуально она есть.

Что проверять командам: не только Tab и Enter в браузере, а активацию через NVDA/JAWS/TalkBack/VoiceOver. Если это меню, кнопка раскрытия должна быть настоящей кнопкой или вести себя как она: один общий механизм открытия, корректное aria-expanded, дочерние пункты доступны после открытия, состояние синхронизировано для мыши, клавиатуры и экранного доступа.
Когда список прокрутился, но экранный доступ молчит

В Flutter завели свежий issue про iOS и VoiceOver: пользователь делает обычную трёхпальцевую прокрутку в длинном списке, список действительно едет, но VoiceOver не говорит ничего вроде «страница 2 из 5» или «строки 6–10 из 43».

Для зрячего человека это легко не заметить: контент сдвинулся, значит прокрутка работает. Для незрячего пользователя это другая ситуация. Он сделал жест и не получил ответа, где теперь находится. В ленте, списке сообщений, настройках или аудиоприложении это быстро превращается в обследование вслепую: «я продвинулся? далеко? не перескочил ли нужный блок?»

Интересная деталь: автор сравнил iOS с Android. TalkBack получает события прокрутки и сам собирает объявление. На iOS строку статуса должен передать сам движок/приложение. В issue прямо указали место в Flutter engine, где для этого до сих пор стоит TODO. Комментарий участника Flutter подтвердил воспроизведение на iPhone: список прокручивается, но позиция не озвучивается.

Вывод для команд простой: проверять нужно не только «можно ли прокрутить». Нужно пройти реальный жест с VoiceOver/TalkBack и послушать, получает ли человек обратную связь после изменения позиции.

Если интерфейс меняет состояние молча, пользователь с экранным доступом остаётся без карты. В длинных списках это не косметика, а часть навигации.

Источник: flutter/flutter#189285
Когда форма ошибается молча

Коротко: новый разбор issue → audit → PR по доступности интерфейса. Полный текст — следующим сообщением.
Когда форма ошибается молча

В OJS и OMP есть похожая проблема в формах регистрации и отправки материалов. Пользователь нажимает «отправить», форма показывает ошибки, но фокус может остаться на кнопке или улететь не туда. Для зрячего это неприятно. Для пользователя с JAWS или VoiceOver это уже риск потеряться: ошибка есть, но где именно чинить поле, непонятно.

Я выбрал для недельного PR не маленькую правку в одном месте, а общий слой валидации форм в pkp-lib. Там сходятся сразу три accessibility-issue: фокус после ошибки, связь поля с текстом ошибки и некорректный aria-invalid.

Что поменялось: после неудачной отправки фокус переходит к первому ошибочному полю, сообщение об ошибке получает стабильный id, поле связывается с ним через aria-describedby, а aria-invalid="true" ставится только пока поле реально невалидно.

Это не делает весь продукт автоматически доступным. Но убирает один типичный барьер: форма перестаёт просто «ругаться где-то на странице» и начинает вести пользователя к месту, которое нужно исправить.

Такие вещи хорошо ловятся не глазами, а обследованием интерфейса: что слышит экранный доступ, куда попадает фокус, понимает ли человек связь между полем и ошибкой. Для этого я и развиваю Accessibility Auditor Skill.

Issues: #12635, #12599, #12837
PR: pkp/pkp-lib#13031
Когда меню есть глазами, но его нет для экранного доступа

В репозитории OpenAI Codex появился свежий issue: в десктопном Codex на Windows меню подсказок открывается визуально, когда пользователь вводит /, но NVDA и JAWS его не видят.

Автор проверил это через Windows UI Automation: при открытии меню дерево доступности не меняется - 0 added, 0 removed, 0 changed. Фокус остаётся в поле ввода, стрелки двигают визуальное выделение, но экранный диктор не слышит ни список, ни текущий пункт.

Для зрячего пользователя это просто удобное меню команд. Для незрячего разработчика это превращается в угадайку: команда вроде бы есть, подсказки вроде бы работают, но выбрать нужный инструмент или режим без визуального контроля нельзя.

Исправление здесь не сводится к «добавьте подписи». Такой компонент нужно проверять как комбинированное поле: поле ввода знает, что управляет списком, список имеет роль, варианты имеют состояние, а активный пункт меняется так, чтобы экранный диктор это объявлял. В веб-интерфейсах это обычно означает aria-haspopup, aria-controls, aria-activedescendant, role="listbox" и role="option" - но важнее не набор атрибутов, а реальная проверка с NVDA/JAWS.

Хороший тест для командных палитр, автодополнения и AI-инструментов: открыть меню с клавиатуры, пройтись стрелками и спросить не «вижу ли я подсветку», а «слышит ли пользователь, какой пункт сейчас выбран и что произойдёт после Enter».
Видео с субтитрами — это ещё не доступный видеоплеер

В Stagebook открыли отдельный issue по MediaPlayer: в компоненте есть свои кнопки play/pause, перемотка, шаг, скорость и поддержка файла субтитров через captionsFile. Но это как раз тот случай, где «субтитры есть» не закрывает задачу.

Если человек не слышит звук, ему нужно не только увидеть текст реплик. Ему нужно включить субтитры, понять состояние плеера, добраться до скорости и перемотки, не потерять фокус и при необходимости получить текстовую версию. Если кнопки иконками без имён, а управление проверили только мышкой, часть людей просто не сможет нормально пройти эксперимент или обучение.

Хорошая проверка для команды простая: пройти медиасценарий без мыши и без звука. Видно ли, где фокус? Понятно ли экранному диктору, какая кнопка что делает? Можно ли включить субтитры и есть ли понятный путь к транскрипту? Учитывается ли prefers-reduced-motion, если в плеере есть движение?

Медиаплеер — это не один тег video. Это рабочий путь: управление, субтитры, текстовая альтернатива, клавиатура и состояние после каждого действия.