Изменяющаяся или «живая» область (live region) — это часть страницы, где происходят изменения, о которых автоматически расскажут пользователям скринридеры и другие вспомогательные технологии.
Раньше скринридеры не умели рассказывать о динамически изменяющемся содержимом. Например, что при отправке формы возникла ошибка или об успешном сохранении изменений. Пользователям приходилось возвращаться в начало и конец блока или целой страницы. Как вы догадались, обычно об изменениях узнавали случайно.
Главная цель изменяющейся области — указать вспомогательным технологиям как правильно обрабатывать изменения содержимого страницы. Выгода для пользователей — они точно узнают обо всех изменениях без лишних нажатий на клавиши.
Когда и как использовать
СкопированоИзменяющиеся области охватывают любое содержимое на странице, которое добавляется, удаляется или загружается. Например:
- ошибки к полям и целым формам;
- сообщения об успешности действий пользователя;
- оповещения;
- прогресс загрузки или удаления;
- логи, чаты с сообщениями, списки друзей, фид;
- таймеры;
- биржевые тикеры, бегущие строки, прогнозы погоды, карусели.
Основные правила использования изменяющихся областей:
- В области находится только изменяющееся содержимое. Не делайте «живой» всю страницу.
- Не делайте изменяющимися областями все части страницы с изменениями. Например, об ошибке в форме рассказать важно, а об изменении названия кнопки не всегда.
- Следите за встроенными в теги свойствами и узнавайте, что делают другие ARIA-атрибуты. Например, достаточно задать кнопке, которая раскрывает меню, состояние
aria
.- expanded - Изменяющимися областями могут быть интерактивные элементы и простой текст. Исключение —
arial
и роль- live = "assertive" alert
. Их добавляют только для текста. - Хорошо связывать элемент, который приводит к изменениям на странице, и изменяющуюся область. Используйте
aria
или- describedby aria
.- labelledby
Чтобы изменяющаяся область заработала, в ней должно что-то поменяться. Если точнее, должен измениться DOM (Document Object Model) и дерево доступности (Accessibility Tree). Есть несколько способов это сделать. Спойлер: во всех случаях нужен JavaScript 🪄
Первый способ — удалить или добавить целый элемент в DOM. Это можно сделать с помощью JavaScript-методов манипуляции с элементами из DOM — .create
, .inner
и так далее. Подробнее в статье «Element».
Также можно менять значения display
с none
на block
, visibility
с hidden
на visible
и удалять и добавлять HTML-атрибут hidden
.
Второй способ — удалить или добавить только содержимое элемента, при этом сам элемент всегда есть на странице. Тут снова поможет JavaScript, особенно метод .text
.
Другой путь — добавлять новое содержимое по мере загрузки страницы или после перезагрузки.
Наконец, можно добавить ARIA-атрибут или роль интерактивной области к элементу, когда это нужно, и затем удалить. Так часто поступают с таймерами.
Как добавить
СкопированоЕсть три способа.
- Использовать теги, в которые уже встроены нужные роли и свойства, —
<output>
и<progress>
. - Задействовать атрибуты
aria
и опционально- live aria
,- busy aria
или- atomic aria
.- relevant - Добавить к тегам специальные ARIA-роли
status
,log
,marquee
,timer
иalert
.
Обычно проблему доступности динамически изменяющегося контента решают с помощью WAI-ARIA или просто ARIA (Web Accessibility Initiative — Accessible Rich Internet Applications).
HTML-теги
СкопированоПервый полезный тег — <output>
. Его используют для вывода результатов. Это могут быть математические расчёты как в калькуляторе или правильное пропущенное слово в предложении в тестах на знание грамматики. Ещё один неочевидный случай использования — всплывающие уведомления или тосты. Это оповещения, которые выезжают внизу или вверху экрана и исчезают через какое-то время.
Внутри тега лучше размещать фразовый контент. Например, заголовки, списки или параграфы. Если вложите внутрь кнопку, ссылку или таблицу, скринридеры могут вас не понять 🤔
Содержимое <output>
автоматические зачитывается скринридерами благодаря встроенной в тег роли status
. Это одна из ролей «живых» областей.
У status
невысокий приоритет объявления. Это значит, что скринридер расскажет об изменениях внутри <output>
после другой, более приоритетной информации. Например, после сообщения о том, что нажата кнопка, или после текста ошибки с ролью alert
.
К сожалению, пока <output>
поддерживается не во всех браузерах и скринридерах. На всякий случай задавайте тегу явную роль status
.
<output role="status"> <!-- Содержимое тега --></output>
<output role="status"> <!-- Содержимое тега --> </output>
Пример всплывающего уведомления с <output>
🧇 Обратите внимание, что кнопку для закрытия уведомления добавляем рядом с изменяющейся областью, а не внутри.
<button>Сохранить</button><div> <output role="status"></output> <button aria-label="Закрыть">X</button></div>
<button>Сохранить</button> <div> <output role="status"></output> <button aria-label="Закрыть">X</button> </div>
Второй тег — <progress>
. Его используют для индикаторов выполнения задач — прогресс-баров. Это может быть индикатор загрузки файла или очистки папки с удалёнными письмами.
В тег по умолчанию встроена роль progressbar
. Это не роль изменяющейся области, но скринридеры всё равно объявляют о прогрессе загрузки в процентах или при помощи особого звукового оповещения.
Не забывайте задавать <progress>
атрибуты max
и value
. Без них скринридеры не смогут отследить прогресс загрузки, когда у неё есть чёткие начало и конец. Так что изменяйте значение value
с помощью JavaScript и явно задавайте значение max
.
Если вложите внутрь <progress>
кнопку, ссылку, заголовок и другие элементы, для вспомогательных технологий это просто текст без встроенных в теги ролей.
Ещё у <progress>
должна быть подпись, чтобы пользователи понимали, что загружается. Для видимой подписи используйте <label>
, а для доступной только вспомогательным технологиям — aria
.
<!-- Подпись с <label> --><label for="progress-bar">Очищаем корзину</label><progress id="progress-bar" max="100" value="0"></progress><label> Очищаем корзину <progress max="100" value="0"></progress></label><!-- Подпись с aria-label --><progress aria-label="Очищаем корзину" max="100" value="0"></progress>
<!-- Подпись с <label> --> <label for="progress-bar">Очищаем корзину</label> <progress id="progress-bar" max="100" value="0"></progress> <label> Очищаем корзину <progress max="100" value="0"></progress> </label> <!-- Подпись с aria-label --> <progress aria-label="Очищаем корзину" max="100" value="0"></progress>
Посмотрим на прогресс-бар на практике. Для подписи используем <label>
, с помощью JavaScript обновим значение атрибута value
и визуальный индикатор в виде числа и заливки.
<label for="progress-bar">Очищаем корзину</label><div>0%</div><progress id="progress-bar" value="0" max="100"></progress><button>Очистить</button>
<label for="progress-bar">Очищаем корзину</label> <div>0%</div> <progress id="progress-bar" value="0" max="100"></progress> <button>Очистить</button>
Бывают ситуации, когда <progress>
связан с другой частью страницы с изменениями. Например, подгружается новое содержимое. При этом неизвестно, где у него начало и конец. В этом случае добавьте к нужной части страницы aria
и свяжите её с прогресс-баром с помощью aria
.
<div role="feed" aria-busy="true" aria-describedby="progress-bar"> <!-- Содержимое, которое сейчас обновляется --></div><progress id="progress-bar" aria-label="Обновление фида"></progress>
<div role="feed" aria-busy="true" aria-describedby="progress-bar"> <!-- Содержимое, которое сейчас обновляется --> </div> <progress id="progress-bar" aria-label="Обновление фида"></progress>
ARIA-атрибуты
СкопированоДругой способ сделать часть страницы изменяющейся областью — специальные ARIA-атрибуты.
Чаще всего достаточно задать элементу aria
со значением polite
. Такие объявления не будут врываться без спроса и прерывать действия пользователей. Хорошие случаи использования — сообщения о сохранении данных, успешной подписке на рассылку, отправки письма и похожие ситуации.
<form> <!-- Поля, чекбоксы и всё, что душе угодно --> <button type="submit" aria-describedby="success">Отправить</button> <span id="success" aria-live="polite"> Мы получили вашу заявку. На обработку уйдёт 3 рабочих дня. </span></form>
<form> <!-- Поля, чекбоксы и всё, что душе угодно --> <button type="submit" aria-describedby="success">Отправить</button> <span id="success" aria-live="polite"> Мы получили вашу заявку. На обработку уйдёт 3 рабочих дня. </span> </form>
Другое значение aria
— assertive
. Используйте его для срочных оповещений, о которых надо рассказать прямо сейчас. Так что применяйте aria
с осторожностью. Значение подойдёт для критически важных ошибок, которые прерывают действия пользователей. Например, когда пропало интернет-соединение и пользователь из-за этого не может отправить заявку.
<form> <!-- Поля, чекбоксы и всё, что душе угодно --> <button type="submit" aria-describedby="fail">Отправить</button> <span id="fail" aria-live="assertive" aria-atomic="true"> У нас проблемы с сервером, так что заявка не отправилась. Нам нужно 5 часов, чтобы всё починить. </span></form>
<form> <!-- Поля, чекбоксы и всё, что душе угодно --> <button type="submit" aria-describedby="fail">Отправить</button> <span id="fail" aria-live="assertive" aria-atomic="true"> У нас проблемы с сервером, так что заявка не отправилась. Нам нужно 5 часов, чтобы всё починить. </span> </form>
Последнее значение aria
— off
. Такие области всё ещё изменяющиеся, но пользователи узнают об изменениях в них только если сделали фокус на них или элементах внутри.
Остальные ARIA-атрибуты изменяющихся областей необязательные и нужны в особых ситуациях.
aria
помогает скринридерам понять, что элемент сейчас изменяется и нужно пока ни о чём не рассказывать и подождать окончания этих изменений.
Атрибут пригодится для сложных компонентов. Например, для фида с ролью feed
или ленты новостей как в социальных сетях. В этом случае можно задать на время загрузки aria
всей области с новостями, а после удалить. Так скринридеры расскажут об изменениях только тогда, когда пользователь нажмёт кнопку «Обновить ленту» и все элементы загрузятся.
<div role="feed" aria-busy="true"> <!-- Тут загружаются посты --></div>
<div role="feed" aria-busy="true"> <!-- Тут загружаются посты --> </div>
aria
рассказывает скринридеру об объёме изменений, о которых надо рассказать. Это вся изменяющаяся область или её часть. Атрибут крайне полезен для таймеров.
Если используете aria
в таймере, вспомогательные технологии будут правильно объявлять текущее время: сначала часы, даже если они не изменились, потом минуты. Без атрибута скринридеры расскажут только об изменившихся минутах.
<div role="timer" aria-live="polite" aria-atomic="true"> <span id="timer-hours"></span> <span id="timer-mins"></span></div>
<div role="timer" aria-live="polite" aria-atomic="true"> <span id="timer-hours"></span> <span id="timer-mins"></span> </div>
aria
сообщает скринридерам, о каком типе изменений рассказать. Это может быть добавление текста или элементов, их удаление или всё вместе. Атрибут особенно полезен в случае чата в мессенджере или обновления списка друзей.
Для добавляющихся элементов используйте значение additions
, для добавляющегося текста — text
, для удаляющегося содержимого — removals
. Когда в изменяющейся области важны все типы изменений, используйте all
.
Если нужно рассказать пользователям об удалении и добавлении содержимого, можно объединить сразу два значения. В этом примере со списком друзей используем aria
.
<ul id="friend-list" aria-live="polite" aria-relevant="additions removals"> <!-- Ссылки на аккаунты друзей --></ul>
<ul id="friend-list" aria-live="polite" aria-relevant="additions removals" > <!-- Ссылки на аккаунты друзей --> </ul>
ARIA-роли
СкопированоПока HTML не покрывает все случаи, когда нужна изменяющаяся область. В этих ситуациях используйте специальные ARIA-роли. Лучше всего задавать их семантически нейтральным <div>
и <span>
, но бывают случаи, когда их можно использовать и для семантических тегов. Например, <p>
.
Добавить к элементу роль очень просто. Задайте role
с нужным значением.
<div role="status"> <!-- Изменяющееся содержимое --></div>
<div role="status"> <!-- Изменяющееся содержимое --> </div>
Чаще всего используют роль status
. Она подходит для любых изменений, о которых скринридерам не надо срочно рассказывать. Например, что письмо успешно отправлено или что покупка оплачена.
У status
невысокий приоритет объявления, так как у неё по умолчанию есть свойства aria
и aria
. Это означает, что скринридеры расскажут обо всём, что происходит в области, но не сразу.
<form> <!-- Элементы формы для оплаты покупки --> <button type="submit" aria-describedby="success"> Оплатить </button> <span role="status" id="success"> Покупка успешно оплачена. Начинаем собирать заказ. </span></form>
<form> <!-- Элементы формы для оплаты покупки --> <button type="submit" aria-describedby="success"> Оплатить </button> <span role="status" id="success"> Покупка успешно оплачена. Начинаем собирать заказ. </span> </form>
log
пригодится для логов. Это отдельный документ или часть страницы, где выводятся в определённой последовательности данные или информация о действиях пользователей или работы программы. Старая информация скрывается по мере добавления новой. Например, log
можно добавить к истории сообщений или для списка ошибок.
log
по умолчанию заданы aria
и aria
, поэтому скринридеры не сразу рассказывают о последних изменениях.
<h2>История сообщений</h2><div role="log"> <ul> <li> Одолжишь своего вельш-корги-кардигана до понедельника? Очень нужно. <time datetime="2077-04-21T12:09">12:09</time> </li> <li> Тебя снова взломали? <time datetime="2077-04-21T13:00">13:00</time> </li> </ul></div>
<h2>История сообщений</h2> <div role="log"> <ul> <li> Одолжишь своего вельш-корги-кардигана до понедельника? Очень нужно. <time datetime="2077-04-21T12:09">12:09</time> </li> <li> Тебя снова взломали? <time datetime="2077-04-21T13:00">13:00</time> </li> </ul> </div>
Когда нужно, чтобы пользователи узнали обо всех изменениях в логах, в том числе старых, используйте aria
. Если это срочные изменения, добавьте aria
.
От роли marquee
веет прошлым. На заре интернета было модно добавлять на сайты бегущие строки. Тогда это делали с помощью тега <marquee>
. Тег устарел, но иногда нужно добавить на сайт блок с быстро изменяющейся информацией. marquee
придумали как раз для таких ситуаций. Роль пригодится для блоков с биржевой информацией и каруселей.
marquee
задан атрибут aria
, так что у роли нет приоритета объявления. Скринридеры не расскажут об изменениях в такой области без фокуса на ней, даже если пользователи сейчас не взаимодействуют со страницей.
<h3>Текущие курсы валют</h3><ul role="marquee"> <li>999 956 $ за юань</li> <li>1 000 000 000 032 $ за докакоин</li></ul>
<h3>Текущие курсы валют</h3> <ul role="marquee"> <li>999 956 $ за юань</li> <li>1 000 000 000 032 $ за докакоин</li> </ul>
Роль timer
говорит сама за себя. Это любая область, в которой ведётся обратный и обычный отсчёт времени.
У timer
нет приоритета объявления, по умолчанию ей задан aria
. Так что с этой ролью рекомендуют дополнительно использовать aria
и aria
.
<div id="clock" role="timer" aria-live="polite" aria-atomic="true"> <span id="clock-mins"></span> <span id="clock-secs"></span></div>
<div id="clock" role="timer" aria-live="polite" aria-atomic="true"> <span id="clock-mins"></span> <span id="clock-secs"></span> </div>
Роль alert
используют редко и только для срочных, важных оповещений. Например, что пропало интернет-соединение или не получилось сделать денежный перевод.
Важный момент в использовании alert
— срочным может быть динамически появляющееся содержимое, а не подгружающееся. Чаще всего это ошибка к форме, которая стала видимой после нажатия на кнопку «Отправить». Ещё задавайте эту роль только тексту. Ссылки и кнопки, простите! В этот раз обойдёмся без вас.
В alert
встроены атрибуты aria
и aria
, так что скринридеры моментально рассказывают обо всём, что происходит в области.
.show { display: inline-block;}
.show { display: inline-block; }
<div role="alert"> <!-- Класс .show добавляется и удаляется JavaScript--> <span class="show"> Изменения не сохранились из-за проблем с сервером. </span></div>
<div role="alert"> <!-- Класс .show добавляется и удаляется JavaScript--> <span class="show"> Изменения не сохранились из-за проблем с сервером. </span> </div>
Все особенности ролей изменяющихся областей в одной таблице.
Роль | Описание | Встроенные атрибуты |
---|---|---|
status | Несрочные изменения. | aria , aria |
log | Изменения в логах. | aria , aria |
marquee | Сменяющаяся информация. | aria |
timer | Отсчёт времени. | aria |
alert | Срочные изменения. | aria , aria |
Песочница
СкопированоВ демке собраны все роли и атрибуты изменяющихся областей. Можете выбрать нужные сочетания и послушать, как скринридеры объявляют в этом случае содержимое. Его можно добавлять и удалять.