Всё про доступность интерфейсов
7 subscribers
116 photos
193 links
Download Telegram
Приватность не помогает, если до экрана нельзя добраться

В SimpleX Chat появился свежий баг-репорт от пользователя VoiceOver на iOS: после начальных экранов кнопки часто плохо подписаны, а закрытие экрана может стать недоступным.

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

В SimpleX Chat появился свежий баг-репорт от пользователя VoiceOver на iOS. Проблема шире одной кнопки: человек пишет, что почти все экраны после старта приложения либо плохо подписаны для VoiceOver, либо ведут себя непредсказуемо.

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

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

Для команд здесь простая проверка. Не ограничиваться экраном входа и парой видимых кнопок. Пройти весь основной путь с VoiceOver: создание профиля, список чатов, чат, поиск, звонки, настройки, закрытие модальных окон. У каждой иконки должно быть человеческое имя, а у каждого действия - понятный результат.

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

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

На этой неделе я выбрал для PR не отдельную кнопку, а семейство форм в smrt-svelte. Это библиотека компонентов: если там поправить базовые поля, улучшение потом расходится по многим интерфейсам.

Проблема была простая и неприятная. Поле могло показать подсказку, ошибку или статус обработки, но само поле не было связано с этим текстом через aria-describedby. Для зрячего пользователя сообщение видно под инпутом. Для пользователя со скринридером это уже не так очевидно: фокус стоит в поле, а важный текст живёт отдельно.

Я открыл PR, который добавляет устойчивую связь между полями и сообщениями в TextInput, TextareaInput, SelectInput, NumberInput и MoneyInput. Ошибочные состояния теперь получают aria-invalid, а динамические сообщения объявляются аккуратно, без переноса фокуса.

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

Доказательства:
issue #1420
PR #1440
Qwen Chat: когда вход уже недоступен

В репозитории Qwen появился свежий issue от незрячего пользователя NVDA. Он пишет, что официальный Qwen Chat для него фактически блокируется сразу в нескольких местах: визуальная CAPTCHA при входе, недоступная загрузка файлов и кнопки, которые NVDA читает просто как button.

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

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

Для команд здесь простой тест. Перед релизом нужно пройти вход, загрузку файла и основные действия с NVDA или другой экранной читалкой. Важно проверить не видимость элементов, а то, есть ли у каждого действия имя, роль, состояние и понятный порядок фокуса.

Источник: QwenLM/Qwen#2253
Тост с Undo может быть недоступен именно тогда, когда он нужен

В issue по Rollercoaster.dev разобрали обычное уведомление с кнопкой Undo. Визуально действие есть, но VoiceOver или TalkBack могут не дать фокус на кнопку: контейнер склеен в один доступный элемент.

Проверять нужно весь сценарий: объявилось ли сообщение, доступна ли кнопка, хватает ли времени до автозакрытия.

Источник: GitHub issue
Тост с Undo может быть недоступен именно тогда, когда он нужен

В GitHub issue по мобильному приложению Rollercoaster.dev разобрали обычный компонент: всплывающее уведомление с кнопкой Undo.

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

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

Отдельно автор issue отмечает, что accessibilityLiveRegion="assertive" помогает на Android, но iOS его игнорирует. Для VoiceOver нужно отдельно вызывать объявление через AccessibilityInfo.announceForAccessibility.

Я бы здесь проверял не только “есть ли роль alert”. Важнее весь сценарий: слышит ли пользователь сообщение, может ли добраться до действия, хватает ли времени, и что происходит, если уведомлений несколько подряд.

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

Источник: Rollercoaster.dev-mobile#264
Антивирус открылся, но молчит

В NVDA обсуждают регрессию: после обновления до 2026.1.1 Avast Premium Security визуально работает, но при обычной навигации Tab/стрелками экранный диктор не произносит элементы.

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

Источник
Антивирус открылся, но молчит

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

Пользователь описал проблему с Avast Premium Security: после обновления до NVDA 2026.1.1 окно Avast визуально открывается, фокус по элементам ходит, но при переходе Tab или стрелками NVDA не произносит названия и типы элементов. Чтобы понять, где сейчас фокус, приходится отдельно нажимать NVDA+Tab или NVDA+Numpad 5. В NVDA 2025.3.3 такого не было.

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

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

Здесь вывод шире Avast и NVDA: если продукт ограничивает доступ assistive tech ради безопасности, это нельзя делать как вечный список «разрешённых» программ без проверки обновлений. После крупного обновления экранного диктора, перехода на другую архитектуру или смены UI нужно пройти главный путь с реальным NVDA/JAWS/Narrator: Tab, стрелки, диалоги, предупреждения, кнопки подтверждения. И проверять не только «видит ли инструмент элементы», а произносится ли фокус в обычном сценарии.

Источник: issue nvaccess/nvda#20286
Дерево классов, которое видно только глазами

В AberOWL нашли проблему с главным деревом иерархии: визуально узлы раскрываются, но для экранного доступа и клавиатуры не хватает семантики дерева и навигации стрелками.
Дерево классов, которое видно только глазами

В AberOWL завели issue про дерево иерархии классов. Снаружи это обычный список: можно раскрывать узлы, выбирать класс, смотреть связи. Но в коде дерево было собрано из div/button без нормальной семантики дерева: без role="tree", role="treeitem", role="group", без aria-expanded/aria-selected и без навигации стрелками.

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

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

В открытом PR к этому issue уже добавили роли tree/treeitem/group, aria-expanded, aria-selected, aria-level, видимый фокус и обработку стрелок: вверх/вниз для перехода, вправо/влево для раскрытия и сворачивания, Enter или пробел для выбора.

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

Источник: bio-ontology-research-group/aberowl2#25
Когда список “говорит” неправильное число пунктов

В Radix UI завели баг по Select: в Chrome на macOS VoiceOver путает позицию пунктов или вообще не говорит “2 из 5”.

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

Полный разбор ниже.
Когда список “говорит” неправильное число пунктов

В Radix UI завели свежий баг по компоненту Select: в Chrome на macOS VoiceOver неправильно озвучивает позицию пункта в списке.

Если значение уже выбрано, при движении по списку можно услышать что-то вроде “Banana, 1 of 3”, хотя пунктов больше. Если значения ещё нет, VoiceOver может сказать только “Banana” - без “2 из 5” и вообще без контекста. В Safari с VoiceOver и в NVDA на Windows автор этого не воспроизвёл.

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

Такие баги особенно неприятны в библиотеках компонентов. Один Select потом разъезжается по формам, фильтрам, настройкам и админкам. Ошибка в озвучке становится не локальным дефектом одного экрана, а повторяемым дефектом во многих продуктах.

Я бы здесь проверял не только “работает ли выбор мышью”. Для списков и выпадающих меню нужен отдельный прогон с VoiceOver, NVDA и разными браузерами: метка пункта, позиция, общее число, выбранное состояние и поведение до выбора значения. Если часть этой информации видна глазами, но не слышна в экранном доступе, компонент ещё не готов.

Источник: radix-ui/primitives#3962
Кнопка есть, но VoiceOver до неё не доходит

В Expensify поймали свежий баг на iOS: в настройках Workspace → Accounting кнопка Connect рядом с NetSuite не получает отдельный фокус VoiceOver.

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

Источник: Expensify/App#93461
Кнопка есть, но VoiceOver до неё не доходит

В Expensify поймали свежий баг на iOS: в настройках Workspace → Accounting кнопка Connect рядом с NetSuite не получает отдельный фокус VoiceOver. Экранный диктор попадает на всю строку провайдера целиком, а не на саму кнопку. Значит, пользователь не может просто дойти до действия и дважды тапнуть, чтобы подключить интеграцию.

В отчёте указаны версия 9.4.6-0, iPhone 12, iOS 26.5; ошибка воспроизводится и на staging, и в production. В комментариях быстро разобрали вероятную механику: строка собрана как неинтерактивный MenuItem, но родительский контейнер всё равно остаётся accessible=true. На iOS такой контейнер схлопывает потомков в один доступный элемент, и вложенная кнопка исчезает как отдельная цель для VoiceOver.

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

Для команд здесь хороший тест: если внутри строки, карточки или пункта меню лежит отдельная кнопка, проверьте не только подпись кнопки. Проверьте порядок фокуса с VoiceOver/TalkBack: строка и вложенная кнопка должны быть разными доступными элементами, а кнопка должна активироваться как кнопка.

И отдельно - не стоит считать interactive=false равным «для экранного диктора всё безопасно». Родительская доступность и группировка потомков могут сломать главный сценарий даже там, где визуальная вёрстка не изменилась.

Источник: Expensify/App#93461
Модальное окно должно забирать фокус при открытии

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

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

В GitHub появился хороший маленький кейс по Yeliztli: в приложении есть семь выезжающих панелей с деталями генетических вариантов. Визуально они ведут себя как модальные окна: открываются поверх страницы, есть затемнение и закрытие по Escape.

Но в issue #703 автор показывает неприятную разницу: четыре панели вообще не объявлены как role="dialog" и aria-modal="true", а ни одна из семи не управляет фокусом.

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

Это особенно неприятно в интерфейсах с важными данными. Если панель показывает детали варианта, лекарства, риска или другого сложного объекта, пользователь должен понимать: где он сейчас, что открылось, как пройти по содержимому и как безопасно вернуться назад.

Я бы проверял такие компоненты не по признаку «оно красиво открылось», а по полному сценарию:

- экранный доступ объявляет диалог;
- фокус при открытии попадает внутрь панели;
- Tab не уходит в фон;
- Escape и кнопка закрытия работают предсказуемо;
- после закрытия фокус возвращается на элемент, который открыл панель.

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

Источник: bioedca/Yeliztli#703
Кейс доступности

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

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

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

Я выбрала этот кейс для недельного PR, потому что это не правка одной страницы. Quasar - компонентный фреймворк, и такие поля потом расходятся по тысячам интерфейсов.

Что поменялось:
- у сообщения об ошибке появился стабильный id;
- QInput теперь добавляет aria-invalid, aria-errormessage и aria-describedby в состоянии ошибки;
- старые aria-describedby не затираются, а дополняются;
- для кастомных контролов через QField slot появились готовые ARIA-значения;
- добавлены тесты на оба сценария.

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

Инструмент, которым я пользуюсь для таких разборов: Accessibility Auditor Skill.

Issue: quasarframework/quasar#17306
PR: quasarframework/quasar#18323