HTML глобальный атрибут inert
Определение и применение
Глобальный атрибут inert (англ. inert — инертный, неактивный) делает элемент и его
потомков недоступными для обычного взаимодействия пользователя. Браузер исключает эту область из
клавиатурной навигации и дерева доступности — представления страницы для вспомогательных технологий.
При этом содержимое остаётся в документе и само по себе не исчезает с экрана.
Например, у карточки ещё загружаются данные, а её кнопки и поля уже видны. В этом случае можно временно сделать всю карточку инертной, оставив сообщение о загрузке и кнопку отмены снаружи. Другой сценарий — боковая панель, которую сдвинули за край экрана: одного перемещения через CSS недостаточно, чтобы убрать её ссылки из обхода клавишей Tab.
Поддержка браузерами
Спецификация: multipage
Поддерживается во всех основных браузерах с 2023 года.
Отдельные значения (1) поддерживаются не везде — смотрите таблицу.
| Возможность | Компьютеры | Мобильные | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
inert | 102 | 102 | 112 | 88 | 15.5 | 102 | 112 | 70 | 15.5 | 19.0 | 102 | 15.5 |
| Element is ignored for the purposes of find-in-page. | 124 | 124 | 120 | 110 | 124 | 120 | 82 | 27.0 | 124 | |||
поддерживаетсяс ограниченияминет поддержкинет данных≤31 — не позднее версии 31
Строка «Element is ignored for the purposes of find-in-page» означает «Элемент не участвует в поиске
по странице». Речь о встроенном поиске браузера: Ctrl + F или
Command + F на macOS. При поддержке этого поведения браузер пропускает текст
внутри инертной области. Отметка «Нет» в этой строке относится только к исключению из поиска,
а не к поддержке самого атрибута inert.
Проверка наличия свойства:
const supportsInert = 'inert' in HTMLElement.prototype;
В старом браузере неизвестный HTML-атрибут не отключит интерфейс. Если блокировка обязательна,
нужен проверенный полифил либо иной сценарий с доступными нативными элементами.
Замена одним pointer-events: none не обеспечивает клавиатурную доступность.
Синтаксис и значения
<section inert>
<h2>Настройки доставки</h2>
<label>Город <input name="city"></label>
<button type="button">Применить</button>
</section>
inert — логический атрибут: значение определяется его наличием.
Записи inert, inert="" и inert="inert" равнозначны.
Чтобы снять инертность, удалите атрибут. Если атрибута нет, элемент всё ещё может быть инертным из-за
предка или открытого модального диалога.
Что происходит с инертной областью
- Ссылки, кнопки и поля не получают фокус при обходе клавишей Tab; обычный вызов
focus()тоже не переносит в них фокус. - Пользователь не может активировать вложенные элементы кликом или отредактировать их содержимое, включая область с
contenteditable(атрибутом, разрешающим пользователю редактировать содержимое элемента прямо на странице). - Элемент и его потомки исключаются из дерева доступности: средство чтения с экрана не должно предлагать их как доступную часть интерфейса.
- Обычное выделение текста пользователем подавляется. По стандарту текст также исключается из поиска по странице. В браузерах, где эта часть поведения не реализована, поиск может находить текст даже внутри инертной области. Поддержка указана в отдельной строке таблицы — пояснение к поиску по странице.
- Размеры, расположение, цвета и прозрачность не меняются автоматически. Видимое объяснение недоступности задаёт автор страницы.
Действие распространяется на потомков в плоском дереве (flat tree): это дерево с учётом
распределения содержимого через слоты Shadow DOM. Поэтому inert применим и к контейнерам
веб-компонентов. Добавленные позже потомки тоже попадают под ограничение; вручную обновлять каждому
tabindex не нужно.
Сравните активную и инертную области в базовом примере. Проверяйте не только мышь, но и Tab, Shift + Tab и редактирование поля.
Управление через JavaScript
const panel = document.querySelector('#settings');
panel.inert = true; // Добавить атрибут.
panel.inert = false; // Удалить атрибут.
panel.toggleAttribute('inert'); // Переключить наличие атрибута.
console.log(panel.inert); // Проверить собственный атрибут.
Свойство HTMLElement.inert отражает атрибут самого элемента, а не вычисляет его фактическую
доступность. Если inert задан контейнеру, у вложенной кнопки button.inert может
быть false, хотя кнопка недоступна. Присваивание button.inert = false не отменяет
инертность предка. Удалите атрибут с нужного контейнера либо разместите действующую кнопку вне него.
Метод toggleAttribute('inert')
добавляет атрибут inert, если его нет, и удаляет, если он есть.
Метод removeAttribute('inert')
удаляет атрибут; если его нет, ничего не меняется. Эти методы изменяют только атрибут самого элемента
и не отменяют инертность, вызванную его предком.
Фокус и доступное объяснение
Фокус определяет, какой элемент сейчас получает ввод с клавиатуры. Например, пользователь вводит
текст в поле внутри карточки. Если нужно сделать карточку инертной, сначала вызовите focus()
у доступной кнопки «Отмена» за пределами карточки, а затем добавьте inert.
Так пользователь сможет продолжить работу с клавиатуры, а фокус не останется в отключаемом поле.
После удаления inert не нужно автоматически возвращать фокус в прежнее поле.
За время загрузки пользователь мог перейти к другому полю и начать печатать там.
Неожиданный перенос фокуса ему помешает. Возвращайте фокус, когда пользователь сам выбрал продолжение
работы с карточкой, например нажал кнопку «Продолжить редактирование».
Сообщение «Загрузка…», объяснение причины блокировки и кнопку «Повторить попытку» размещайте
за пределами элемента с inert. Если оставить их внутри, кнопка тоже перестанет работать,
а программа чтения с экрана не сможет прочитать сообщение.
Блоку с изменяющимся сообщением можно задать role="status": это позволяет программе
чтения с экрана озвучить новый текст без переноса фокуса на него. Атрибут aria-busy="true"
сообщает такой программе, что содержимое области ещё обновляется. Он не блокирует кнопки и ссылки
и не заменяет inert.
Визуальное обозначение инертной области
Атрибут inert сам по себе не меняет внешний вид элемента. Чтобы показать, что область
временно недоступна, можно сделать её полупрозрачной с помощью свойства
opacity:
[inert] {
opacity: 0.5;
}
Такой стиль делает изменение заметным, но не объясняет его причину. Дополните его текстом за пределами
контейнера. Селектор [inert] выбирает только элементы с явным атрибутом, а не всех фактически
инертных потомков. В примере переключения области
кнопка управления и сообщение остаются доступны при обоих состояниях.
Отличия от других способов отключения и скрытия
| Средство | Назначение и отличие |
|---|---|
inert | Временно исключает целую область из взаимодействия и дерева доступности, сохраняя её отображение. |
disabled | Отключает поддерживающий его элемент формы. Отключённое поле не участвует в отправке и проверке ограничений формы. Для группы полей есть fieldset disabled; обычные ссылки внутри группы он не отключает. |
readonly | Запрещает изменение значения поддерживаемого текстового поля, сохраняя возможность фокусировки, копирования и отправки значения. Не блокирует произвольный контейнер. |
hidden | Скрывает неактуальное содержимое визуально и от вспомогательных технологий. Режим until-found имеет отдельные правила раскрытия. |
aria-hidden="true" | Убирает содержимое из дерева доступности, но само по себе не препятствует кликам и фокусу. Нельзя оставлять внутри доступные с клавиатуры элементы. |
aria-disabled="true" | Сообщает о недоступности элемента, но не отключает его автоматически. Поведение, фокус и оформление реализует автор. |
pointer-events: none | Меняет обработку указателя; не исключает ссылки из клавиатурной навигации и дерева доступности. |
tabindex="-1" | Исключает один элемент из последовательного обхода. Не отключает его потомков, клики или программную фокусировку. |
Связь с dialog и popover
Нативный <dialog>,
открытый через showModal(), автоматически делает остальной документ инертным.
Вручную добавлять inert на все соседние блоки не требуется. Метод show()
и обычный атрибут open не создают такую модальность.
Модальный диалог — специальное исключение: он может выйти из инертности предков. При этом явный
inert на самом диалоге отключит и его. У обычного потомка такого исключения нет.
Это различие можно проверить в примере модального диалога.
popover
создаёт немодальную всплывающую область и не делает фон инертным. Сам выход элемента в верхний слой
отображения не освобождает его от inert предка. Для обязательного ответа пользователя
обычно подходит модальный диалог, а не сочетание всплывающей панели с самодельной блокировкой страницы.
Ограничения и типичные ошибки
- Не помещайте единственную кнопку включения внутрь отключаемого контейнера: пользователь не сможет её нажать.
- Не используйте
inertдля важного пояснения, которое нужно прочитать во время блокировки. - Не считайте атрибут защитой данных: скрипты могут читать и менять DOM, выполнять обработчики через программную отправку событий. Таймеры и сетевые запросы не останавливаются.
- Не принимайте
element.inert === falseза универсальную проверку интерактивности: учитывайте предков и модальные диалоги. - Сам атрибут не создаёт диалог, не назначает ему доступное имя, не управляет прокруткой и не реализует весь жизненный цикл модального окна.
Спецификация
HTML Living Standard: inert и инертные поддеревья.
Примеры, попробуйте сами
Активная и инертная область
Сравните ввод текста и обход элементов клавишей Tab. Удалите inert у второй области: её элементы станут доступны. Затем попробуйте inert="false" — наличие атрибута снова отключит область. Пример требует нативной поддержки inert.
index.html
<h2>Активная область</h2>
<div>
<label>Город <input value="Казань"></label>
<label><input type="checkbox"> Нужна доставка</label>
<button type="button">Продолжить</button>
</div>
<h2>Область для проверки inert</h2>
<p>Измените атрибут контейнера и сравните доступность элементов.</p>
<div inert>
<label>Город <input value="Томск"></label>
<label><input type="checkbox"> Нужна доставка</label>
<button type="button">Продолжить</button>
</div>
style.css
[inert] {
opacity: 0.5;
}
Переключение инертности
Нажмите , затем отключите область внешней кнопкой. Проверьте поле и Tab, после чего включите область. Кнопка внутри области показывает безопасный порядок действий: сначала перенос фокуса наружу, затем inert = true.
index.html
<button id="toggle" type="button" disabled>Отключить область</button>
<p id="status" role="status">Запустите пример, чтобы проверить inert.</p>
<section id="settings" aria-labelledby="settings-title">
<h2 id="settings-title">Настройки</h2>
<p><label>Название проекта <input id="project" value="Мой сайт"></label></p>
<p><label><input type="checkbox"> Получать уведомления</label></p>
<button id="lock" type="button" disabled>Отключить изнутри</button>
</section>
main.js
const panel = document.querySelector('#settings');
const toggle = document.querySelector('#toggle');
const lock = document.querySelector('#lock');
const statusMessage = document.querySelector('#status');
if (!('inert' in HTMLElement.prototype)) {
statusMessage.textContent = 'Браузер не поддерживает inert. Откройте пример в более новом браузере.';
} else {
toggle.disabled = false;
lock.disabled = false;
statusMessage.textContent = 'Область доступна.';
function setLocked(locked) {
// Переносим фокус до отключения области, если он находится внутри неё.
if (locked && panel.contains(document.activeElement)) {
toggle.focus();
}
panel.inert = locked;
toggle.textContent = locked ? 'Включить область' : 'Отключить область';
statusMessage.textContent = locked ? 'Область временно недоступна.' : 'Область доступна.';
}
toggle.addEventListener('click', () => {
setLocked(!panel.inert);
});
lock.addEventListener('click', () => {
setLocked(true);
});
}
style.css
[inert] {
opacity: 0.5;
}
Нажмите , чтобы запустить пример.
Модальный диалог внутри inert
Нажмите и откройте диалог: showModal() позволяет ему работать внутри инертного предка, а фон становится недоступен. Закройте его кнопкой или Escape. Замените showModal() на show() и повторите: немодальный диалог останется инертным; закройте его внешней кнопкой.
index.html
<button id="open" type="button" disabled>Открыть диалог</button>
<button id="close-outside" type="button" disabled>Закрыть снаружи</button>
<p id="status" role="status">Запустите пример.</p>
<div inert>
<p>Этот контейнер инертен.</p>
<button type="button">Недоступная кнопка</button>
<dialog id="dialog" aria-labelledby="dialog-title">
<h2 id="dialog-title">Проверка диалога</h2>
<p>Модальный диалог может выйти из инертности предка.</p>
<button id="close" type="button" autofocus>Закрыть</button>
</dialog>
</div>
main.js
const dialog = document.querySelector('#dialog');
const openButton = document.querySelector('#open');
const closeButton = document.querySelector('#close');
const closeOutside = document.querySelector('#close-outside');
const statusMessage = document.querySelector('#status');
if (!('inert' in HTMLElement.prototype) || typeof dialog.showModal !== 'function') {
statusMessage.textContent = 'Для примера нужны inert и dialog.showModal().';
} else {
openButton.disabled = false;
closeOutside.disabled = false;
statusMessage.textContent = 'Откройте диалог и проверьте фокус.';
openButton.addEventListener('click', () => {
// Замените на show(), чтобы сравнить с немодальным диалогом.
dialog.showModal();
});
closeButton.addEventListener('click', () => {
dialog.close();
});
// Нужна для закрытия инертного диалога после замены showModal() на show().
closeOutside.addEventListener('click', () => {
dialog.close();
});
}
Нажмите , чтобы запустить пример.