Всё про доступность интерфейсов
7 subscribers
116 photos
193 links
Download Telegram
В Signal Desktop меню есть, но NVDA до него не добирается

В свежем issue к Signal Desktop пользователь описал Windows-кейс: с NVDA можно открыть «New chat», дойти до кнопки «Manage contact» рядом с контактом и нажать Enter. Визуально появляется pop-out menu, но экранный диктор его не видит: ни Tab, ни команды NVDA не дают выбрать пункты.

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

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

После Enter/Space надо пройти сами пункты: фокус попал внутрь, роли и названия читаются, Escape закрывает слой, фокус возвращается на «Manage contact».

Источник: signalapp/Signal-Desktop#7982
Граф, который нельзя обойти с клавиатуры

В PatternFly React Topology завели issue: узлы и связи в topology-view визуально есть, но для клавиатуры и экранного диктора почти исчезают. `withSelection()` реагирует на мышь, а у узлов нет фокуса, клавиатурной активации и понятных имён для озвучивания.

Это не абстрактное «ARIA не проставили». Источник пишет, что в большом приложении на Ansible UI такие графы используются для workflow. Мышью можно ткнуть в шаг процесса. Человек, который работает с клавиатуры, switch control или NVDA/JAWS, может не попасть на этот шаг и не понять, где ошибка, куда двигаться дальше и что связано с чем.

Для графов, карт, схем, kanban-досок и pipeline-экранов проверка простая: можно ли пройти элементы Tab/стрелками, услышать имя и состояние каждого узла, активировать его Enter/Space и понять связи без картинки.

Если ответ «нет», интерфейс показывает структуру только тем, кто может пользоваться мышью.
Терминал, который видно только глазами

В T3 Code открыли issue про встроенный терминал: он рисуется в canvas и помечен aria-hidden. Для NVDA это стена: вывод команды не читается, введённый текст выглядит пустым, а при нескольких терминалах непонятно, какая сессия активна.

Это не задача уровня «добавить пару подписей». В coding-инструменте терминал — часть основного рабочего пути. Если пользователь без зрения не может прочитать stdout, ошибку или свой ввод перед Enter, агентный интерфейс становится декоративным.

Минимально полезное решение: читаемый буфер со scrollback как обычный фокусируемый текст + ненавязчивый сигнал, что команда завершилась. VS Code пришёл к похожей модели через accessible view терминала.

Проверка для команды: запустить команду с NVDA/JAWS/VoiceOver и ответить честно — можно ли прочитать вывод, проверить ввод, понять активный терминал и вернуться к результату?

Источник: pingdotgg/t3code#5500
Когда доступность включает тяжёлый режим приложения

В Status App завели issue: на Redmi A5 Android-приложение после логина может зависнуть, если включён TalkBack, Switch Access или другой accessibility service.

Без такого сервиса тот же путь медленный, но стабильный. С ним приложение перестаёт отвечать больше чем на 5 секунд, Android показывает ANR, а TalkBack в этот момент тоже молчит. Для зрячего пользователя это «приложение подвисло». Для пользователя экранного диктора это ещё и потеря ориентации: экран не отвечает и ничего не говорит.

Сильная деталь: проблема не в подписи кнопок. Похоже, Qt-слой доступности синхронно ждёт дерево элементов, пока основной интерфейс занят тяжёлой работой после логина. Доступность добавляет настоящую нагрузку к сценарию.

Командам стоит прогонять первый запуск и логин на слабом устройстве с TalkBack/Switch Access: слабое железо, включённый экранный доступ, первые 30 секунд после входа. Иначе интерфейс может быть формально доступным, но зависать как раз у тех, кому он нужен.
Когда интерфейс говорит слишком точно

В MuseScore обсуждают маленькую, но очень показательную проблему: при навигации по нотам экранный диктор может произносить позицию так: «measure 1, beat 3.666667».

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

Хороший вывод для любых интерфейсов: текст для assistive tech не обязан быть буквальной копией того, что видно на экране. Если на экране можно показать техническое значение, то в речи лучше дать короткую, понятную форму: округлить число, заменить машинную дробь словами или вынести отдельную фразу специально для screen reader users.

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

Нашла хороший свежий сигнал в Visual Framework: для компонента vf-video завели issue про доступность YouTube-вставок.

С виду всё обычно: компонент получает ссылку на видео и рисует iframe. Но в аудите нашли простую вещь - у iframe нет title. Для зрячего пользователя это просто ролик на странице. Для screen reader user это может быть безымянная рамка: непонятно, что открылось, зачем оно здесь и стоит ли в это заходить.

Интересно, что issue не сводится к «добавьте один атрибут». Там отдельно обсуждают:

- сделать название видео обязательным или хотя бы явно предупреждать авторов;
- как связать компонент с транскриптом;
- убрать autoplay из разрешений по умолчанию и включать его только осознанно.

Это уже затрагивает не одну группу пользователей. Незрячему человеку нужен понятный объект в дереве доступности. Глухому или слабослышащему - нормальный путь к текстовой версии. Человеку, чувствительному к резкому звуку или движению, не нужен компонент, который заранее разрешает автозапуск просто «на всякий случай».

Вывод для команд простой: если у вас есть общий video/embed-компонент, проверяйте не только сам плеер. Проверьте контракт компонента:

1. есть ли у iframe понятное имя;
2. есть ли рядом ссылка на транскрипт или понятный способ её задать;
3. не включён ли autoplay по умолчанию;
4. говорит ли документация авторам, что именно они обязаны передать.

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

Источник: visual-framework/vf-core#2427
Комбобокс — отдельный интерфейсный сценарий

У Gradio был показательный баг: listbox/combobox в приложениях на Gradio почти не работал с NVDA/Narrator. Для AI-инструментов это критично: человек может открыть приложение, но застрять уже на выборе модели, голоса, файла или режима.

Полный разбор — следующим сообщением.
Комбобокс — отдельный интерфейсный сценарий

У Gradio в этом году был хороший показательный баг: незрячий пользователь Pinokio написал, что listbox/combobox в приложениях на Gradio почти не работает с NVDA/Narrator. Обход через object navigation есть, но сам автор прямо пишет: пользоваться так непрактично.

Почему это важно. Gradio стал стандартным UI-слоем для множества AI-инструментов. Если dropdown выбора модели, голоса, файла или режима не читается как нормальный combobox, человек может открыть приложение, но застрять на базовой настройке.

Команда признала проблему в кастомном multi-select combobox и позже закрыла issue через PR с ARIA-pattern для Dropdown/Listbox.

Что проверять у себя:
• элемент имеет понятные name/role/value;
• экранный диктор слышит выбранный пункт и количество вариантов;
• стрелки, Enter, Escape работают предсказуемо;
• состояние selected/expanded меняется и визуально, и в дереве доступности;
• старый скрытый select не торчит вторым «мусорным» listbox рядом с новым контролом.

Кастомный dropdown можно делать. Но тогда его надо тестировать как самостоятельный сценарий, а не как стилизованный div.

Источник: https://github.com/gradio-app/gradio/issues/12855
Не каждый фокус после клика — accessibility fix.

В Chakra UI / Zag завели issue про Splitter.ResizeTrigger: после перетаскивания разделителя мышью ручка остаётся в фокусе, и стрелки продолжают менять размер панели.

Полный разбор — следующим сообщением.
Не каждый фокус после клика — accessibility fix.

В Chakra UI / Zag завели issue про Splitter.ResizeTrigger: после перетаскивания разделителя мышью ручка остаётся в фокусе. Визуально это выглядит как активное keyboard-состояние, а следующие нажатия стрелок продолжают менять размер панели — хотя человек уже закончил drag и мог хотеть пролистать страницу или перейти по форме.

Автор важную вещь формулирует просто: ARIA window splitter должен быть доступен с клавиатуры, но это не значит, что pointer-drag обязан оставлять фокус на ручке.

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

Что проверять в resize/splitter-компонентах: Tab → фокус → стрелки работают; после mouse drag фокус не притворяется keyboard-фокусом; :focus-visible не загорается от программного pointer-фокуса; если элемент был сфокусирован клавиатурой до drag, это состояние сохраняется аккуратно.

Доступность — это не “добавить фокус везде”. Иногда наоборот: не смешивать состояния.
Хороший маленький кейс из macOS-приложения Notify GCal Menu.

В приложении делали меню в строке macOS: кнопки с иконками, выпадающий выбор времени напоминания, подсказки горячих клавиш вроде ⌘S и ⌘Q.

Визуально всё аккуратно. Но для VoiceOver такая полировка легко превращается в шум или пустоту.

Что нашли в PR:

• Picker «Notify me» визуально имел подпись, но из-за .labelsHidden() сам контрол оставался без понятного контекста для VoiceOver. Исправили отдельным accessibilityLabel("Notify me").

• Заголовок «NOTIFICATIONS» сделали настоящим ориентиром для VoiceOver через .accessibilityAddTraits(.isHeader).

• Текстовые подсказки «⌘S» и «⌘Q» спрятали от экранного диктора: сами шорткаты уже подключены через .keyboardShortcut, а чтение символов вслух только мешает.

Отдельно проверили контраст скриптом. Там нашлась важная деталь: часть системных цветов Apple не проходит 4.5:1 для обычного текста в некоторых состояниях. Команда оставила их как есть, потому что это нативные semantic colors macOS, и переопределение могло бы сделать приложение менее похожим на остальную систему.

Но две проверки остались ручными: живой проход VoiceOver по popover и проверка крупного системного текста / Dynamic Type без обрезки и наложений.

Вывод простой: доступность нативного интерфейса не заканчивается на «у нас стандартные контролы». Нужно пройти реальный путь:

• что слышит VoiceOver у каждого контрола;

• не читаются ли декоративные символы как полезная информация;

• остаётся ли интерфейс usable при крупном тексте;

• не заменяет ли скрипт контраста живую проверку с ассистивной технологией.

Особенно это касается маленьких popover-меню: там мало места, и одна безымянная кнопка или обрезанный текст быстро ломают весь сценарий.
Календарь может быть «доступным» с клавиатуры — и всё равно ломаться на iPhone с VoiceOver.

Свежий пример: issue в Vaadin DatePicker. Подробности — следующим сообщением.
Календарь может быть «доступным» с клавиатуры — и всё равно ломаться на iPhone с VoiceOver.

В issue по Vaadin DatePicker описали неприятную штуку: с iOS VoiceOver пользователь не может нормально уйти дальше текущего месяца. Список месяцев не прокручивается как нужно, следующий календарь не получает фокус, а при движении по датам VoiceOver читает только число: «10», «11», «12». Без месяца и контекста это почти бесполезно.

Почему так вышло: компонент опирается на обычный DOM-фокус и roving tabindex. Но iOS VoiceOver в календарной сетке может двигаться своим способом, не передвигая DOM-фокус туда, где его ждёт компонент. В итоге часть календарей остаётся `aria-hidden`, хотя визуально интерфейс вроде бы есть.

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

Что проверять командам:

• реальные жесты VoiceOver на iOS, а не одни Tab/стрелки на десктопе;
• можно ли перейти на следующий месяц без визуального контроля;
• объявляется ли дата целиком, а не один день месяца;
• не прячете ли вы `aria-hidden` то, куда экранный доступ должен попасть;
• есть ли запасной путь: обычные select-поля месяца/года или текстовый ввод даты.

Roving tabindex — не гарантия доступности. Он работает только пока assistive technology действительно следует вашей модели фокуса. Если платформа навигирует иначе, нужен тест на реальном устройстве, а не только «правильная ARIA-схема» в коде.
График есть, а цифры для части пользователей исчезают

В Kibana завели issue про histogram на странице Discover: Tab полностью пропускает график, поэтому keyboard-only и screen-reader пользователи не могут добраться до смысла визуализации.

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

Источник: elastic/kibana#284830
График есть, а цифры для части пользователей исчезают

В Kibana завели показательный issue: на странице Discover histogram-график вообще не достигается с клавиатуры. Нажимаешь Tab - фокус просто проходит мимо. Для keyboard-only пользователя и для человека со скринридером это означает не «неудобно посмотреть график», а «невозможно получить смысл визуализации».

Здесь важная деталь: клавиатура может быть основным способом работы из-за моторных ограничений, травмы руки, тремора, switch control, удалённого рабочего окружения или просто потому, что мышью работать тяжело. Если график живёт только на hover, клике и зрении, он отсекает больше людей, чем кажется.

В issue хорошо сформулировано ожидаемое поведение: график должен быть достижим с клавиатуры, а его значения - доступны скринридеру. Это можно делать по-разному: фокусируемые элементы графика, понятная текстовая сводка, таблица, отдельная расшифровка по периодам. Главное - не оставлять единственный путь через мышь и зрение.

Ещё интереснее комментарий в обсуждении: недоступные charts/graphs в Kibana встречаются в разных местах, поэтому это завели как более общий platform issue. И это честная проблема многих интерфейсов: визуализация переиспользуется как компонент, но доступный контракт для неё не задан.

Что проверять командам:

1. Можно ли дойти до графика с клавиатуры?
2. Понятно ли, что это за график и что он показывает?
3. Можно ли прочитать значения без hover и без зрения?
4. Есть ли таблица, summary или другой текстовый путь к тому же смыслу?
5. Не ломается ли сценарий, если пользователь работает через VoiceOver, NVDA, JAWS или только клавиатурой?

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

Источник: elastic/kibana#284830
WordPress Gutenberg поймал хороший accessibility-баг не про скринридеры, а про крупный текст.

В редакторе есть настройка Show button text labels: она заменяет часть иконок в тулбарах текстовыми подписями. Для многих людей это не косметика, а способ не гадать по пиктограммам.

Но в новом Tabs block тулбар становится слишком широким и может уезжать за край экрана.

Источник: WordPress/Gutenberg issue #81679
В WordPress Gutenberg появился показательный баг: новый Tabs block ломает тулбар, если включить настройку Show button text labels.

Это настройка из раздела Accessibility. Она делает кнопки понятнее: не только иконка, но и текстовая подпись. Для слабовидящих пользователей, людей с когнитивной нагрузкой, новичков и тех, кто просто не узнаёт иконки, это часто решает реальную задачу: не вспоминать, что означает очередной значок.

Проблема в том, что у внутреннего блока Tab List подписи в тулбаре получаются слишком длинными. Тулбар разрастается по ширине и на небольшом экране может частично скрываться.

И тут интересный момент. В обсуждении быстро заметили: это проблема не одного Tabs block. Если интерфейс нормально выглядит только когда все действия спрятаны в короткие иконки, значит команда тестирует слишком узкий сценарий. А когда включаются текстовые подписи, крупный текст или перевод на язык с длинными словами, макет внезапно перестаёт быть рабочим.

Что я бы проверяла в таких компонентах:

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

Доступность иногда ломается не потому, что забыли aria-label. Иногда команда просто нарисовала интерфейс только для идеального размера, идеального языка и идеального пользователя.

Источник: WordPress/Gutenberg issue #81679
Кнопка «скопировать» сработала, но пользователь об этом не услышал

Свежий issue по Microsoft Foundry Local: после нажатия copy в блоке «Start with SDK» команда копируется, визуально появляется успех, а экранный диктор его не объявляет.

Это не мелочь про ARIA. Это обратная связь после действия: пользователь должен понять результат без визуального поиска по странице.

Полный разбор ниже.
Кнопка «скопировать» сработала, но пользователь об этом не услышал

В свежем issue по Microsoft Foundry Local описали простой, но очень показательный сбой: на главной странице есть кнопка copy в блоке «Start with SDK». Команда копируется, визуально появляется сообщение об успехе, а экранный диктор это сообщение не объявляет.

Для зрячего пользователя это мелочь: увидел «copied» и пошёл дальше. Для пользователя NVDA, JAWS или Narrator это уже неопределённость: кнопка не сработала, команда в буфере, надо нажать ещё раз, или теперь нужно вручную искать изменившийся текст на странице?

Здесь ломается не сама кнопка, а обратная связь после действия. И это касается не только незрячих. Такая же проблема бьёт по людям с когнитивной нагрузкой, по тем, кто работает в спешке, и по любому интерфейсу, где результат действия временный: copy, save, upload, retry, отправка формы.

Что проверять командам:

• сообщение об успехе или ошибке попадает в live region;

• для спокойных статусов подходит role="status" / aria-live="polite";

• для срочных ошибок - role="alert";

• live region уже есть в DOM до того, как туда вставляют текст;

• после нажатия пользователь может понять результат без мыши и без визуального поиска по экрану.

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

Источник: microsoft/foundry-local#1012
Pressable не становится кнопкой сам по себе

В свежем issue по assistant-ui заметили: 19 React Native action-компонентов рендерятся через Pressable без accessibilityRole. Для VoiceOver и TalkBack это может звучать не как кнопка, а как обычный generic element.

Если компонент ведёт себя как кнопка, роль лучше задавать в primitive/design-system слое, а не на каждом экране вручную.
В React Native есть неприятная ловушка: Pressable делает элемент фокусируемым, но сам по себе не говорит экранному диктору, что это кнопка.

В свежем issue по assistant-ui это поймали на мобильных примитивах библиотеки. В @assistant-ui/react-native 19 action-компонентов рендерятся через Pressable без accessibilityRole. В итоге VoiceOver и TalkBack могут объявлять такие элементы как обычный generic element, а не как кнопку.

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

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

В React Native Pressable не равен кнопке для доступности.

Если компонент ведёт себя как кнопка, ему нужен явный accessibilityRole="button". Лучше задавать это на уровне дизайн-системы или primitive-компонента, а не надеяться, что каждый экран не забудет роль вручную.

Минимальная проверка для команды:

• Взять все `Pressable`, `Touchable*` и кастомные action-компоненты.

• Проверить, есть ли у них роль, имя и состояние.

• Прогнать хотя бы основной сценарий с VoiceOver и TalkBack.

• Отдельно проверить маленькие icon-only действия: именно они чаще всего выглядят очевидно глазами и бессмысленно звучат голосом.

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

Источник: GitHub issue assistant-ui#6117