Когда мы говорим про скринридеры, почти все сначала думают так: «Ну он просто читает HTML со страницы».

Это не так.

Скринридер не видит экран, не читает HTML напрямую, и не “ходит” по странице, как человек с мышкой.

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

Как браузер «показывает» страницу скринридеру

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

  1. DOM — что вообще есть на странице

  2. Accessibility Tree — что из этого важно человеку

  3. Accessibility API — как браузер передаёт это скринридеру

Скринридер работает не с HTML, а только с тем, что браузер передал ему через эти уровни.

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

DOM — «что вообще есть»

Представьте ситуацию из жизни.

Вы переехали в новую квартиру.  В комнате стоят коробки.
На каждой есть подпись:

  • «Посуда»

  • «Одежда»

  • «Документы»

  • «Книги»

По этим надписям вы можете догадываться, что внутри.
Но вы не знаете точно:

  • хрупкое ли там содержимое,

  • можно ли коробку переворачивать,

  • стоит ли открывать её прямо сейчас,

  • есть ли внутри что-то важное или срочное.

Надпись даёт намёк, но не инструкцию.

Именно так работает DOM.

Вернёмся к браузеру.

Представьте, что браузер открывает страницу и видит элемент с текстом «Купить». И всё.

Браузер не знает, что это:

  • кнопка,

  • ссылка,

  • важное действие,

  • или просто текст на странице.

Он видит только факт: На странице есть элемент. Внутри — текст «Купить»

<div>Купить</div>

Для DOM это означает ровно одно:

  • есть div,

  • внутри него текст.

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

Так что такое DOM на самом деле

DOM — это полный список всего, что лежит на странице, с точки зрения браузера:

  • заголовки,

  • абзацы,

  • кнопки,

  • ссылки,

  • картинки,

  • и порядок, в котором всё это расположено.

DOM фиксирует: «Вот что есть и вот где это находится».

Но он не объясняет смысл элементов и не говорит, как с ними взаимодействовать.

Почему это важно для доступности

Зрячий пользователь считывает смысл визуально:

  • по форме кнопки,

  • по цвету,

  • по расположению.

Скринридер этого не видит.  Он ориентируется только на то, что явно описано в DOM и семантике. Если смысл не задан — пользователь остается в неопределённости.

Accessibility Tree — «что это значит для человека»

Если DOM — это просто коробки на складе (они есть, стоят в каком-то порядке, на них что-то написано), то Accessibility Tree — это момент, когда к этим коробкам наконец появляется инструкция.

Браузер смотрит на DOM и решает:

  • это вообще важно пользователю?

  • с этим можно взаимодействовать?

  • это нужно читать вслух?

  • или это просто декор и можно игнорировать?

В Accessibility Tree попадает не всё, что есть в DOM.

Представьте склад.

Коробки те же самые, но теперь:

  • не все коробки внесены в опись,

  • к важным добавлены пояснения,

  • стало понятно, что с ними делать.

На коробке появляется не просто слово, а смысл:

  • что это за предмет,

  • можно ли с ним взаимодействовать,

  • насколько он важен.

Например:

  • «Кнопка. Основное действие. Можно нажать».

  • «Заголовок. Описывает раздел».

  • «Поле ввода. Нужно ввести имя».

Accessibility Tree — это перевод DOM на человеческий язык.

Как это выглядит в браузере

Возьмём простой пример.

<button>Купить</button>

В Accessibility Tree это превращается в:

  • роль: кнопка

  • имя: «Купить»

Скринридер скажет: Кнопка. Купить.

Теперь другой вариант:

<div class="btn">Купить</div>

Для DOM это просто:

div с текстом «Купить»

Но в Accessibility Tree:

  • нет роли

  • нет имени

  • нет взаимодействия

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

Почему это вообще важно

Скринридер не читает страницу сверху вниз как человек. Он ориентируется по структуре.

Если в Accessibility Tree:

  • нет кнопки,

  • нет заголовка,

  • нет имени у поля,
    то для пользователя: этого просто не существует.

Именно поэтому:

  • визуально «красивый» интерфейс может быть полностью недоступным,

  • а семантически простой интерфейс — понятным и управляемым.

Accessibility API — «переводчик для скринридера»

Accessibility API — это канал связи между браузером и скринридером.

Важно сразу зафиксировать ключевую мысль: Скринридер не читает HTML, не смотрит страницу, не знает, что такое DOM.

Скринридер общается только с Accessibility API.

Как это работает в реальности

Есть три участника:

  1. Браузер (Chrome, Safari, Firefox)

  2. Accessibility API (часть операционной системы)

  3. Скринридер
    – VoiceOver (macOS, iOS)
    – NVDA, JAWS (Windows)
    – TalkBack (Android)

Скринридер задаёт вопросы API:

  • Что вообще есть на экране?

  • Какие элементы важные?

  • В каком порядке по ним идти?

  • Это кнопка или просто текст?

  • Можно ли с этим взаимодействовать?

API отвечает ему уже готовыми, структурированными данными.

Аналогия

  • DOM → коробки

  • Accessibility Tree → опись с пояснениями

  • Accessibility API → способ передать эту опись человеку, который не видит склад

Есть нюанс: Человек не видит склад.

Он не может:

  • подойти к коробке,

  • прочитать надпись,

  • увидеть, что она важная.

Ему нужен кто-то, кто зачитает опись вслух. Вот эту роль и выполняет Accessibility API.

Как это работает в браузере

  1. Сначала браузер строит DOM — полную техническую модель страницы.

  2. Затем на его основе формирует Accessibility Tree — отфильтрованную и осмысленную структуру для пользователя.

  3. И только эту структуру через Accessibility API он передаёт скринридеру.

«Коробка. Кнопка. Основное действие. Можно нажать.»
«Коробка. Заголовок. Начало раздела.»
«Коробка. Поле ввода. Нужно ввести имя.»

Скринридер не смотрит страницу напрямую.

Пример в браузере

<button>Купить</button>

Что происходит дальше:

  1. HTML → попадает в DOM

  2. Из DOM → формируется Accessibility Tree

  3. Из дерева → данные уходят в Accessibility API

API передаёт скринридеру:

  • роль: кнопка

  • имя: «Купить»

  • состояние: доступна

Скринридер читает: «Кнопка. Купить.»

Почему Accessibility API — критически важно

Если элемент:

  • не попал в Accessibility Tree

  • не имеет роли

  • не имеет имени

  • не имеет состояния

то API не сможет передать его скринридеру.

А значит: Для пользователя этого элемента не существует.

Экран для разбора: форма входа

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

Как экран выглядит для обычного пользователя

Зрячий пользователь видит привычную картину:

  • затемнённый фон сайта,

  • модальное окно по центру,

  • заголовок «Вход с помощью пароля»,

  • поля для логина и пароля,

  • чекбокс «Запомнить меня»,

  • ссылку «Восстановить пароль»,

  • основную кнопку «Войти»,

  • вторичную «Отменить»,

  • крестик закрытия в углу.

Что при этом есть «под капотом»

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

  • DOM — просто набор элементов: div’ы, инпуты, кнопки, ссылки.
    Он не знает, что это диалог, где главное действие и что фон сейчас недоступен.

  • Accessibility Tree — версия страницы, которую браузер считает важной для человека. Сюда должны попасть заголовок, поля ввода, кнопки и ссылки, а фон — наоборот, исчезнуть.

  • Accessibility API — канал, через который браузер передаёт эту структуру скринридеру.

Что в идеале должен услышать пользователь скринридера

Если всё реализовано корректно, сценарий звучит примерно так:

«Диалог. Вход с помощью пароля.»
«Заголовок первого уровня. Вход с помощью пароля.»
«Поле ввода. Номер телефона или почта.»
«Поле ввода. Пароль. Защищенное.»
«Кнопка. Показать пароль.»
«Флажок. Запомнить меня.»
«Ссылка. Восстановить пароль.»
«Кнопка. Войти.»
«Кнопка. Отменить.»

Фокус не уходит за пределы модального окна.

Где чаще всего всё ломается

На практике именно такие экраны часто дают сбой:

  • модальное окно не объявлено как диалог,

  • фон остаётся доступным для навигации,

  • у иконки «глаз» нет имени,

  • крестик закрытия — без aria-label,

  • Tab-порядок скачет или уводит пользователя «под окно».

В итоге человек слышит не форму входа, а случайный набор элементов страницы.

При проверке окна входа на Суточно.ру со скринридером выяснилось, что модальное окно не попадает в accessibility tree. Скринридер продолжает читать элементы основного сайта, игнорируя визуально открытое окно авторизации.
При проверке окна входа на Суточно.ру со скринридером выяснилось, что модальное окно не попадает в accessibility tree. Скринридер продолжает читать элементы основного сайта, игнорируя визуально открытое окно авторизации.

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

Подобная ситуация обычно возникает, когда модальное окно реализовано без role="dialog", aria-modal="true" и корректного управления фокусом.

Для сравнения можно посмотреть, как реализовано окно входа в Яндекс ID.
При проверке со скринридером модальное окно авторизации читается как единый логический блок: сначала объявляется заголовок окна, затем — список доступных аккаунтов и действия. Фокус корректно переводится внутрь диалога, а фон страницы исключается из навигации.

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

Почему роль дизайнера здесь важнее, чем кажется

Доступность ломается не в коде, а раньше — в решениях.

Именно дизайнер задает:

  • это заголовок или просто крупный текст;

  • это кнопка или «кликабельный прямоугольник»;

  • у поля есть лейбл или его заменили плейсхолдером;

  • ошибка объясняется словами или только красной рамкой;

  • понятно ли, что происходит, если не видеть экран.

Разработчик может сделать всё «по макету».
А вот будет ли этот макет понятен скринридеру — решается на этапе дизайна.

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

Я выложила его в Figma Community, чтобы им можно было пользоваться в работе, сохранять и адаптировать под свои проекты.