Скринридеры

Что такое скринридеры, как они устроены и работают, почему для них важна семантическая вёрстка и как их тестировать.

Время чтения: 13 мин

Сайтами и приложениями пользуются разные люди. Кто-то может это делать с любого устройства, а другим нужны вспомогательные технологии (assistive technology). Это такие программы и устройства, которые упрощают взаимодействие пользователей с особыми потребностями с контентом. К примеру, выносные кнопки, трекболы, брайлевские дисплеи, экранные лупы и скринридеры.

Трекбол, брайлевский дисплей и три разноцветные выносные компьютерные кнопки.

Одна из самых популярных вспомогательных технологий — скринридеры 🤖

Кратко

Скопировано

Скринридер (screen reader) — программа, которая превращает контент интерфейсов в речь или шрифт Брайля. Другие названия — программа экранного доступа или чтения, программа чтения с экрана и экранное считывающее устройство.

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

Слабовидящие пользователи могут сочетать скринридеры с другой вспомогательной технологией — экранной лупой (screen magnification). Она увеличивает контент на экране и тоже его озвучивает, если это нужно.

Устройство

Скопировано

Скринридеры состоят из двух частей:

  • Программная оболочка — интерфейс программы.
  • Движок синтеза речи — способ преобразования текста в речь.

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

Движки тоже могут отличаться, но чаще всего используют формантный синтез речи (Formant Text-to-Speech). Он основан на искусственных звуках, которые имитируют человеческую речь. Плохо передаёт эмоции, зато тексты зачитываются на любой скорости без потери качества. Это важно, ведь многие люди слушают интерфейсы с высокой скоростью.

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

Виды скринридеров

Скопировано

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

  • Windows — JAWS (платный и скачиваемый), NVDA (бесплатный и скачиваемый) и Narrator (бесплатный и предустановленный).
  • macOS и iOS — VoiceOver, предустановлен.
  • Android — TalkBack, предустановленный.
  • Linux — Orca, тоже установлен по умолчанию в системе.
  • Chrome OS — ChromeVox, предустановленный. Можно скачать как расширение в браузеры на Chromium.

Более полный список можно найти в Википедии.

У скринридеров разная популярность среди пользователей, как у браузеров. Следить за статистикой можно через ежегодные опросы пользователей WebAIM. Это американская компания, которая занимается доступностью. Есть и исследование русскоговорящих пользователей скринридеров (проводилось в 2023).

В лидеры чаще всего попадают:

  • JAWS и Chrome, NVDA и Firefox или Chrome. Периодически меняются местами.
  • Десктопный и мобильный VoiceOver и Safari.
  • TalkBack и Chrome.

Эта статистика полезна для тестирования и помогает понять, в каких скринридерах лучше тестировать в первую очередь.

Как работают скринридеры

Скопировано

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

Программа не берёт контент сразу из вкладки браузера. Это происходит через посредника — Accessibility API (Accessibility Application Programming Interface). В свою очередь, браузеры передают Accessibility API данные об элементах со страницы в виде дерева доступности (acessibility tree).

Схема взаимодействия браузеров, скринридеров и Accessibility API. Браузеры создают DOM-дерево, потом дерево доступности на его основе, отдают его API, а он передаёт нужную информацию скринридерам.

Скринридеры могут взаимодействовать и с другими API, но давайте подробнее разберёмся с Accessibility API и деревом доступности.

Accessibility API

Скопировано

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

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

Есть несколько реализаций Accessibility API.

Браузеры умеют поддерживать сразу несколько API.

Дерево доступности

Скопировано

Это представление элементов документа в виде дерева на основе DOM (Document Object Model). Похоже на DOM-дерево, только состоит не из HTML-элементов, а из объектов доступности (accessible object).

Объект доступности состоит из роли, имени, описания, свойств и состояний.

Во многие семантические теги роли уже встроены. Роль <a>link, <header>banner, <ul>list. Полный список можно найти на странице с HTML-элементами и именами. Поэтому для доступности важна семантическая вёрстка. Если вместо <button> использовать <div> с событием onclick, то у него не будет роли кнопки и её поведения. Пользователи скринридеров не узнают, что элемент кликабельный.

Как взаимодействуют браузеры, скринридеры и Accessibility API

Скопировано

Представим, что пользователь скринридера добрался до кнопки «Отправить»:

  1. Сначала скринридер запрашивает информацию о кнопке.
  2. Accessibility API получает запрос и передаёт его браузеру.
  3. Браузер проверяет DOM и находит нужный элемент и его стили.
  4. Теперь браузер может преобразовать элемент из DOM в понятный формат для Accessibility API. Это и есть объект из дерева доступности с именем и ролью. После этого браузер отдаёт его API.
  5. API возвращает эту информацию скринридеру.
  6. Скринридер объявляет: «Отправить, кнопка». Ура!
Схема чтения кнопки скринридером. Программа запрашивает элемент у Accessibility API, он передаёт его браузеру, браузер находит кнопку в документе, отдаёт API имя «Отправить» и роль «button», скринридер получает от API имя и роль элемента и зачитывает их.

Теперь пользователь решил нажать на кнопку, чтобы что-то отправить:

  1. Скринридер вызывает метод из Accessibility API.
  2. Accessibility API идёт к браузеру и сообщает о вызове метода.
  3. Браузер ищет и обрабатывает событие с учётом того, есть ли обработчик события.
  4. Представим, что на сайте есть скрипт, который отслеживает события. В этом случае он выполняется, и происходит нужное действие при клике на кнопку.
Схема нажатия на кнопку. Скринридер запрашивает метод у Accessibility API, он передаёт этот метод браузеру, браузер находит скрипт с обработчиком события, в итоге выполняется какая-то функция при клике на кнопку.

Особенности навигации

Скопировано

Навигация со скринридерами по страницам и экранам отличается от обычной.

Клавиатурный фокус устанавливается только на интерактивных элементах. Например, на кнопках и ссылках. Пользователи переходят от одного элемента к другому и так перемещаются по интерфейсу.

Скринридеры при навигации с клавиатуры тоже могут устанавливать фокус на интерактивных элементах и перемещаться по ним, делая при этом объявления. Но это не самый удобный способ навигации для людей, которые не видят интерфейс. Поэтому у пользователей скринридеров есть другой, более удобный вариант — навигация по неинтерактивным элементам. С помощью специальных шорткатов в разных скринридерах открываются списки элементов со страницы. Так можно перемещаться по заголовкам, параграфам, строкам, ориентирам (landmark regions) и другим элементам. Один из самых популярных способов такой навигации — заголовки.

На скриншоте в VoiceOver открыт список всех заголовков из статьи на Википедии.

Статья про говорящего мангуста Джефа. Поверх страницы открыто окно со списком заголовков и их уровнями: 1. Джеф, 2. Содержание, 2. История феномена, 3. Начало «военных действий и примирение» и другие.

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

Дополнительно скринридеры могут зачитывать всё подряд.

Из видео Молли Бёрк вы узнаете, как выглядит на практике навигация с помощью VoiceOver на телефоне и ноутбуке.

Режимы взаимодействия

Скопировано

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

Режим чтения также называют виртуальным или режимом просмотра. В нём скринридеры последовательно зачитывают текст страницы. При этом пользователи могут не только слушать текст, но и перемещаться с помощью стрелок по символам или целым словам, заголовкам, таблицам, ориентирам и другому содержимому страницы, а также открывать меню со всеми ссылками, кнопками и прочим.

Режим фокуса иногда называют режимом форм. В нём скринридеры работают с разными элементами форм — полями, чекбоксами, радиокнопками, выпадающими списками и обычными кнопками для отправки данных.

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

Тестирование

Скопировано

У браузеров и скринридеров разная поддержка HTML, CSS и ARIA. Из-за этого объявление контента может отличаться, а где-то могут попадаться специфическое поведение или баги.

Возьмём для примера список со ссылками из демки и послушаем его в разных скринридерах.

Открыть демо в новой вкладке

Расшифровка видео:

  • NVDA 2021.2 и Chrome 95: «Список из 3 элементов. Рыбы, ссылка. Пёсели, ссылка. Лягухи, ссылка».
  • JAWS 2022 и Chrome 95: «Список из 3 элемента. Рыбы, ссылка. Пёсели, ссылка. Лягухи, ссылка».
  • TalkBack на Android 10 и Firefox 94.1: «Рыбы, элемент списка, 2 из 3. Роль «список», 3 пункта. Пёсели, элемент списка, 3 из 3. Лягухи, элемент списка, 4 из 3». Объявляет информацию об элементах на английском, не зачитывает роль ссылки и неправильно считает элементы списка (баг).
  • VoiceOver и Safari 15.1: «Рыбы, ссылка. Пёсели, ссылка. Лягухи, ссылка». Не объявляет, что это список из трёх элементов из-за свойства list-style со значением none. Оно сбрасывает семантику списка для этого скринридера.

Чтобы не столкнуться с неожиданной проблемой во время тестирования, можно заранее узнать о поддержке HTML и ARIA скринридерами:

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

  1. Навигация по интерфейсу с клавиатуры найдёт многие проблемы до тестирования со скринридерами.
  2. Тестируйте минимум в одном скринридере на поддерживаемых платформах. Выбрать популярные виды помогут опросы пользователей WebAIM.
  3. Проверяйте интерфейсы не только в последних версиях скринридеров и браузеров, но и в более ранних. Пользователи с особыми потребностями не так быстро обновляют программы.
  4. Обращайте внимание на комбинации скринридеров и браузеров. Если программа ведёт себя странно только в одном браузере, то это могут быть особенности совместимости или баг.

Больше практических рекомендаций собрано в руководстве BBC по тестированию со вспомогательными технологиями.

У разных скринридеров есть свои шорткаты и жесты, о которых полезно знать при тестировании:

Не обязательно тестировать с реальными скринридерами. Это можно сделать в BrowserStack и в специальном сервисе от Assistiv Labs.

Учитывайте, что реальные пользователи используют скринридеры постоянно и выработали особенные паттерны взаимодействия с интерфейсами. К тому же, они слушают контент на очень высокой скорости. И это быстрее, чем двойная скорость на YouTube! Так что ручное тестирование поможет обнаружить основные проблемы, но полностью не заменит пользовательское.

Выводы

Скопировано

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

Скринридер озвучивает контент интерфейсов и помогает пользователям проходить через него разными способами. Это могут быть интерактивные и неинтерактивные элементы.

Озвучивать контент скринридерам помогают Accessibility API и браузеры, которые создают дерево доступности. Часть элементов попадает в дерево вместе со встроенными ролями, доступными именами, дополнительным описанием и способами взаимодействия с ними.

У разработчиков уже есть несколько клёвых инструментов, чтобы сделать доступный интерфейс для скринридеров. Это HTML, CSS, иногда ARIA и JavaScript.

Не всегда получается сразу написать хороший интерфейс. Здесь на помощь приходит тестирование, особенно ручное.

Больше узнать о скринридерах помогут эти ссылки:

На практике

Скопировано

Татьяна Фокина советует

Скопировано

🛠 Сделать сайт базово доступным для скринридеров лучше всего с помощью семантической вёрстки. Для этого не нужно делать отдельную версию для пользователей со слепотой и слабовидящих или использовать оверлей. Это дешевле, лучше для пользователей и безопаснее с точки зрения соблюдения законов о доступности. Например, так не будут нарушены Раздел 508 американского закона о реабилитации 1973 года или Европейский стандарт EN 301 549.

🛠 Иногда CSS-свойства могут влиять на структуру. В статье уже упоминались display: none и visibility: hidden, которые скрывают от скринридеров элементы. И также list-style: none, которое отменяет семантику списка в VoiceOver. Есть и другие коварные свойства:

  • width: 0 и height: 0 тоже убирают элемент из дерева доступности.
  • display: table изменяет роль на table.
  • text-transform: uppercase превращает в ранних версиях VoiceOver слова в акронимы. Например, текст кнопки «ВОЙТИ» он прочтёт с паузами между буквами.
  • В дерево доступности попадает содержимое псевдоэлементов ::before и ::after.

А вот свойство order влияет только на визуальное отображение элементов и не изменяет порядок табуляции и объявления элементов.

🛠 Чтобы таблица была доступна для скринридеров, не забывайте использовать тег <th>. В него оборачиваются заголовки ячеек или строк. Он нужен по двум причинам:

Улучшить таблицы для скринридеров помогут дополнительные подписи. Например, в <caption>.

🛠 Когда нужно скрыть неинтерактивный элемент только от скринридеров, используйте атрибут aria-hidden. В этом примере скрываем эмодзи-буллит внутри параграфа.

        
          
          <p>  <span aria-hidden="true">🦄</span>  Неважно, что у машины под капотом. Самое главное, кто сидит за рулём.</p>
          <p>
  <span aria-hidden="true">🦄</span>
  Неважно, что у машины под капотом. Самое главное, кто сидит за рулём.
</p>

        
        
          
        
      

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

🛠 Используйте вспомогательный класс .visually-hidden или .vh, если хотите визуально скрыть элемент, но оставить его для скринридеров.

        
          
          .visually-hidden {  position: absolute;  width: 1px;  height: 1px;  margin: -1px;  padding: 0;  border: 0;  clip-path: inset(0, 0, 0, 0);  overflow: hidden;}
          .visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  clip-path: inset(0, 0, 0, 0);
  overflow: hidden;
}

        
        
          
        
      

Если поддерживаете старые браузеры, используйте вместе с clip-path устаревшее свойство clip: rect(0 0 0 0).

Так можно скрыть <h1>, если его нет в макете, или добавлять для кнопок и ссылок с иконками или картинками тексты.

Добавим скрытый текст «Закрыть» для кнопки с SVG-иконкой.

        
          
          <button>  <svg viewBox="0 0 70 70" xmlns="http://www.w3.org/2000/svg">    <!-- Описание фигуры -->  </svg>  <span class="visually-hidden">Закрыть</span></button>
          <button>
  <svg viewBox="0 0 70 70" xmlns="http://www.w3.org/2000/svg">
    <!-- Описание фигуры -->
  </svg>
  <span class="visually-hidden">Закрыть</span>
</button>

        
        
          
        
      
Открыть демо в новой вкладке