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

Каждый браузер обязательно должен построить DOM и посадить дерево доступности.

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

Дерево доступности (accessibility tree) — это представление элементов документа в виде дерева на основе DOM (Document Object Model, Объектная модель документа). Благодаря дереву доступности вспомогательные технологии, например, скринридеры, знают про содержимое страницы и что на ней происходит.

Как создаётся

Скопировано

В дерево доступности попадает информация о том, как свёрстана страница. Больше всего на него влияет HTML, чуть меньше CSS и JavaScript. При этом дерево доступности не полностью копирует DOM-дерево. Например, в него не попадают элементы со свойствами display: none, visibility: hidden, атрибутом hidden или декоративные <div>.

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

Одно и то же дерево доступности может быть разным в зависимости от браузера. К примеру, могут отличаться названия ролей и по-разному вычисляться имена элементов.

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

Объекты доступности

Скопировано

Дерево доступности состоит из объектов доступности (accessible object). Каждый объект представляет один элемент интерфейса и может содержать роль, имя, описание, свойства и состояния.

Пример части дерева с тремя объектами. У основной части нет имени и есть роль main. У заголовка h1 имя «Товары», роль heading и уровень один. Имя поля input — «Адрес», роль textbox и описание «Улица, дом». У кнопки button имя «Купить», роль button и на ней устанавливается фокус.

У большинства семантических тегов по умолчанию есть нужные роли, имена и состояния, однако их можно явно задавать и изменять с помощью ARIA (Accessible Rich Internet Applications). Это вспомогательная техника для создания более доступного содержимого для скринридеров и других вспомогательных технологий. Расширяет возможности HTML с помощью специальных атрибутов и ролей.

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

Объекты доступности попадают в дерево, если произошло одно из двух событий:

  • элемент, его содержимое, свойства и отношения с другим на странице важны для вспомогательных технологий;
  • сработало доступное событие — пользователь зашёл на сайт со скринридером, экранной лупой и так далее.

Теперь давайте подробнее разберём все части объекта доступности.

Роль

Скопировано

Описывает то, что это за объект и можно ли с ним взаимодействовать. Бывают встроенными и явными.

Встроенные роли есть по умолчанию у семантических тегов. Например, у ссылки <a> с атрибутом href есть роль link:

        
          
          <a href="/cozy-page/">Уютная страница</a>
          <a href="/cozy-page/">Уютная страница</a>

        
        
          
        
      

Даже в <span> и <div> встроена роль generic, но это не добавляет им нужной семантики 🤯

Явные роли задают с помощью ARIA. К примеру, лёгким движением руки <span> превращается в ссылку благодаря атрибуту role="link", CSS и JavaScript.

        
          
          <span role="link">Уютная страница</span>
          <span role="link">Уютная страница</span>

        
        
          
        
      

На практике лучше так не делать и использовать по максимуму возможности HTML. Тогда не придётся писать скрипт, чтобы сделать <span> настоящей ссылкой со всеми нужными свойствами и поведением.

Подробнее с концепцией ролей познакомитесь в статье «ARIA-роли».

Имя

Скопировано

Другое название — доступное имя (accessible name). Если просто, то это подпись к объекту доступности. Имена — важная часть опыта пользователей, которые слушают интерфейсы. Они помогают разобраться, что это за элемент и какая у него цель. Обычно озвучиваются при фокусе и берутся из текстового содержимого тегов или атрибутов.

Вернёмся к примеру со ссылкой. В её случае имя берётся из текста между открывающим и закрывающим тегами — «Уютная страница».

        
          
          <a href="/cozy-page/">Уютная страница</a>
          <a href="/cozy-page/">Уютная страница</a>

        
        
          
        
      

С полями всё ещё проще. Их имя берётся из тега <label>, когда он связан с полем атрибутом for. В этом примере это «Любимый покемон».

        
          
          <label for="pokemon">Любимый покемон:</label><input type="text" id="pokemon">
          <label for="pokemon">Любимый покемон:</label>
<input type="text" id="pokemon">

        
        
          
        
      

Если у <button> нет текста, пользователи вспомогательных технологий узнают только о том, что это какая-то кнопка.

        
          
          <button type="button"></button>
          <button type="button"></button>

        
        
          
        
      

Имена могут браться и из атрибутов aria-label и aria-labelledby. Например, имя этой кнопки с иконкой внутри — «Сделать комплимент».

        
          
          <button aria-label="Сделать комплимент">  <!-- Иконка --></button>
          <button aria-label="Сделать комплимент">
  <!-- Иконка -->
</button>

        
        
          
        
      

У способов предоставления имён есть разные особенности и приоритетность. Подробнее узнаете из спецификации Accessible Name and Description Computation 1.1.

Описание

Скопировано

Другие названия — доступное описание (accessible description) или вспомогательный текст (helper text). Это дополнение к имени, которое подробнее рассказывает об объекте или содержит подсказку к нему. Озвучивается после имени и роли, если выбрана такая настройка в скринридере.

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

У некоторых элементов описания берутся из специальных тегов. Для <figure> это <figcaption>, для <table><caption>, а для <svg><desc>.

Попробуем добавить общее описание к картинкам в <figure>:

        
          
          <figure>  <img src="dog-1.png" alt="Чихуахуа">  <img src="dog-2.png" alt="Карликовый пинчер">  <figcaption>    Хотя внешне чихуахуа похожи на карликовых пинчеров,    это абсолютно разные породы. Они были выведены в разных    странах независимо друг от друга.  </figcaption></figure>
          <figure>
  <img src="dog-1.png" alt="Чихуахуа">
  <img src="dog-2.png" alt="Карликовый пинчер">
  <figcaption>
    Хотя внешне чихуахуа похожи на карликовых пинчеров,
    это абсолютно разные породы. Они были выведены в разных
    странах независимо друг от друга.
  </figcaption>
</figure>

        
        
          
        
      

Что интересно в примере выше, у картинок также есть имена. В случае тега <img> имя берётся из атрибута alt.

Описания к элементам можете добавить и с помощью aria-describedby, aria-details и aria-description.

Например, описание этой кнопки — «Выберите любимый цвет, и он появится на фоне страницы». Оно берётся из <span> с текстом, который связан с <button> атрибутом aria-describedby.

        
          
          <button  type="button"  aria-describedby="hint">  Выбрать тему</button><span id="hint">  Выберите любимый цвет, и он появится  на фоне страницы.</span>
          <button
  type="button"
  aria-describedby="hint"
>
  Выбрать тему
</button>

<span id="hint">
  Выберите любимый цвет, и он появится
  на фоне страницы.
</span>

        
        
          
        
      

Свойства и состояния

Скопировано

Содержат детали о раскладке и возможных действиях с объектами. К примеру, выбран или нет сейчас элемент, связан ли с ним другой и так далее.

Во многие семантические теги, кроме роли, встроены ещё свойства и состояния. Например, у чекбоксов есть атрибут checked. Он сообщает вспомогательным технологиям, что сейчас выбрано. В этом примере кому-то точно нравится пицца с ананасом 🍍

        
          
          <label for="pineapple">  Люблю пиццу с ананасом:</label><input id="pineapple" type="checkbox" checked>
          <label for="pineapple">
  Люблю пиццу с ананасом:
</label>
<input id="pineapple" type="checkbox" checked>

        
        
          
        
      

Свойствами и состояниями можно управлять и с помощью ARIA. Есть ARIA-атрибуты, которые дублируют атрибуты из HTML, как aria-checked.

        
          
          <span id="label">  Люблю пиццу с ананасом:</span><span  role="checkbox"  aria-labelledby="label"  aria-checked="true"></span>
          <span id="label">
  Люблю пиццу с ананасом:
</span>
<span
  role="checkbox"
  aria-labelledby="label"
  aria-checked="true"
>
</span>

        
        
          
        
      

Есть уникальные ARIA-атрибуты, которые передают вспомогательным технологиям ещё больше информации об элементах. Например, aria-expanded сообщает о том, свёрнуто или нет связанное содержимого. В этом примере список товаров пока свёрнут.

        
          
          <button  aria-expanded="false"  aria-controls="list">  Все товары</button><ul id="list">  <!-- Список ссылок --></ul>
          <button
  aria-expanded="false"
  aria-controls="list"
>
  Все товары
</button>
<ul id="list">
  <!-- Список ссылок -->
</ul>

        
        
          
        
      

Подробнее про свойства и состояния рассказываем в статье «ARIA-атрибуты».

Как отлаживать

Скопировано

На дерево доступности можно посмотреть через браузерные инструменты разработчика.

Chrome, Edge

Вкладка «Специальные возможности» (Accessibility) из основной панели «Элементы» (Elements).

Дополнительно можете включить экспериментальную настройку «Дерево доступности на всю страницу» (Enable full-page accessibility tree), выбрав соответствующий чекбокс в аккордеоне «Дерево доступности» (Accessibility Tree). В этом случае в блоке со структурой страницы появится переключатель с фигурой человека для смены вида дерева.

Второй способ. Настройки (Settings) > вкладка «Экспериментальные функции» (Experiments) > чекбокс «Включить дерево доступности на всю страницу в панели "Элементы"» (Enable full accessibility tree view in the Elements panel).

Firefox

Настроить инструменты разработчика и получить помощь (Customize developer tools and get help) > Настройки (Settings) (можно открыть клавишей F1) > чекбокс «Поддержка доступности» (Accessibility) в разделе с инструментами разработчика по умолчанию. После этого появится отдельная вкладка «Поддержка доступности».

Safari

Вкладка «Узел» (Node) в основной панели «Элементы» (Elements) > аккордеон «Специальные возможности» (Accessibility).

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

Заглянем в дерево доступности в Chrome, которое получилось на основе DOM-дерева главной страницы Доки. Визуально оно напоминает иерархию папок в системе, где вместо папок — узлы, а вместо их названий — роли тегов. На скриншоте есть четыре больших узла с хедером banner, основной частью страницы main, футером contentinfo и диалоговым окном dialog. Внутри крупных узлов есть другие, поменьше. К примеру, в banner есть секция section, текстовое поле textbox и тексты «Дока» и «/» (косая черта).

Дерево доступности всей страницы в Chrome. Описание перед картинкой.

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

Вкладка «Доступность» в Chrome. Описание перед скриншотом.

Давайте теперь посмотрим на реальный объект доступности. Возьмём поле <input type="email"> для почты из попапа с подпиской на рассылку Доки.

        
          
          <label class="subscribe-popup__label">  <input    class="subscribe-popup__input"    type="email"    name="email"    placeholder="dog@doka.guide"    inputmode="email"    required  >  <span class="subscribe-popup__hint">    Оставьте вашу почту  </span></label>
          <label class="subscribe-popup__label">
  <input
    class="subscribe-popup__input"
    type="email"
    name="email"
    placeholder="dog@doka.guide"
    inputmode="email"
    required
  >
  <span class="subscribe-popup__hint">
    Оставьте вашу почту
  </span>
</label>

        
        
          
        
      
  • Name — имя поля из <label>. Это «Оставьте вашу почту».
  • Role — встроенная роль элемента. Это textbox.
  • Invalid user entry: false — в поле пока нет неправильных данных.
  • Focusable: true — на элемент можно сделать фокус с клавиатуры.
  • Editable: plaintext — поле редактируется и принимает только текст.
  • Can set value: true — можно задать любое дополнительное значение.
  • Multi-line: false — поле однострочное, нельзя перейти на новую строку.
  • Read-only: false — поле не только для чтения и в него можно вводить данные.
  • Required: true — поле обязательно для заполнения из-за атрибута required.
  • Labelled by — название поля берётся из <label> с классом .subscribe-popup__label.
Информация об объекте доступности в Chrome. Описание перед скриншотом.

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

Подробнее про работу с деревом доступности в разных браузерах:

AOM

Скопировано

Пока что к дереву доступности нет прямого доступа, поэтому им нельзя управлять или читать его напрямую. Объектная модель доступности (Accessibility Object Model или коротко AOM) решит эту проблему в будущем. Это экспериментальное API (Application Programming Interface, Интерфейс программирования приложения), которое позволит разработчикам получить прямой доступ к дереву доступности.

Что ещё почитать

Скопировано

Дополнительные ссылки по теме для пытливых умов 🧠