Атрибут hidden убирает элемент со страницы целиком: он не занимает места, не попадает на экран и недоступен скринридеру. Использовать его можно с любым HTML-элементом. Указывать значение не нужно - достаточно добавить hidden в открывающий тег.
<p>Этот текст виден всем</p>
<p hidden>А этот не рендерится вообще</p>
В этой статье
- Атрибут hidden в HTML: что это и как работает
- Как CSS переопределяет hidden
- hidden="until-found": скрыто, но находится через поиск на странице
- input type="hidden" - это не атрибут hidden
- hidden и aria-hidden: разные задачи
- Переключение hidden через JavaScript
- Частые ошибки с атрибутом hidden
- Шпаргалка по атрибуту hidden
Атрибут hidden в HTML: что это и как работает
У hidden три способа записи, и все они дают один результат - скрытое состояние: пустой атрибут <p hidden>, явное значение hidden="hidden" и даже случайная опечатка вроде hidden="bananas". Любое значение, кроме специального until-found (о нём ниже), браузер трактует одинаково - элемент не рендерится, то есть у него в буквальном смысле нет коробки на странице: он не влияет на расположение соседних элементов, как будто его вообще не существует в разметке.
Это отличает hidden от display: none по происхождению, хотя эффект похож: hidden - это HTML-атрибут, он применяется даже если CSS сайта вообще не загрузился, например в режиме чтения браузера.
Как CSS переопределяет hidden
Скрытое состояние - не железное правило, а обычное поведение браузера по умолчанию, и CSS его перебивает. Если явно задать display элементу с hidden, он снова станет видимым, хотя атрибут hidden из разметки никуда не денется.
Пример: правило CSS побеждает hidden
<div hidden>Текст внутри элемента с hidden</div>
<div hidden id="over">Тот же hidden, но со своим правилом display</div>
div[hidden]#over {
display: block;
}
У второго блока добавлено правило div[hidden]{display:block} - оно побеждает hidden, хотя атрибут в разметке остался.
Отсюда практическая ловушка: достаточно случайного правила с подходящей специфичностью - например, селектора по классу, который задаёт элементу display: flex или display: block - и hidden перестаёт прятать элемент, хотя в разметке он на месте. Чтобы hidden всегда побеждал, в сбросе стилей иногда специально поднимают его приоритет: [hidden] { display: none !important; }.
hidden="until-found": скрыто, но находится через поиск на странице
У hidden есть специальное значение - hidden="until-found". Элемент с ним скрыт визуально, но не выпадает из поиска по странице (Ctrl+F) и из перехода по якорной ссылке на его id. Когда браузер находит внутри такого элемента совпадение или переходит по якорю, он сам снимает атрибут hidden, показывает содержимое и прокручивает страницу к нему - без единой строчки JavaScript для самого раскрытия. Если нужно среагировать на этот момент из кода - например, подгрузить контент лениво - перед самым снятием атрибута на элементе срабатывает событие beforematch.
Пример: hidden="until-found" раскрывается переходом по ссылке
<a href="#payload">Перейти к блоку</a>
<div id="payload" hidden="until-found">Текст, скрытый до перехода</div>
document.getElementById("payload")
.addEventListener("beforematch", () => {
// сработает перед тем, как браузер снимет hidden
});
До перехода по ссылке блок пуст - виден только его тонкий контур, текста нет. После перехода срабатывает beforematch, hidden снимается сам, текст появляется.
Контур блока в демо виден ещё до раскрытия - это не баг. У until-found, в отличие от обычного hidden, элемент не теряет коробку целиком: браузер использует content-visibility: hidden, при котором поля, рамка и фон элемента всё ещё участвуют в раскладке страницы, пропускается только содержимое. Обычный hidden такой коробки не оставляет вовсе.
input type="hidden" - это не атрибут hidden
Атрибут hidden и <input type="hidden"> - разные механизмы, несмотря на общее слово в названии. Атрибут hidden можно указать на любом теге, и он прячет этот тег со страницы. <input type="hidden"> - это отдельный тип поля формы: он и так никогда не показывается на экране сам по себе, его задача - незаметно для пользователя хранить и отправлять значение вместе с формой, например id записи или csrf-токен. У такого поля hidden-атрибут не нужен: тип уже делает его невидимым, а задача у них разная - скрыть тег вообще или хранить служебное значение формы.
hidden и aria-hidden: разные задачи
hidden и aria-hidden="true" прячут элемент по-разному. hidden убирает его отовсюду разом - и с экрана, и из того, что считывает скринридер. aria-hidden="true" трогает только восприятие скринридером: элемент остаётся виден на экране, просто скринридер его пропускает. Это разные задачи - hidden для содержимого, которое не нужно вообще никому, aria-hidden для декоративных или дублирующих вещей, которые зрячему пользователю видеть нормально, а скринридеру незачем озвучивать - например, иконка рядом с текстом той же ссылки.
Важная тонкость: aria-hidden не убирает фокусируемость. Если внутри элемента с aria-hidden="true" остаётся ссылка или кнопка, она всё ещё получает фокус по Tab, хотя скринридер её не объявляет - это несоответствие важно учитывать при скрытии интерактивных блоков.
Переключение hidden через JavaScript
Переключить hidden из скрипта можно двумя способами с одинаковым результатом: через свойство element.hidden, которое отражает тот же атрибут, или через универсальный toggleAttribute.
Пример: два способа переключить hidden
const box = document.getElementById("box");
// способ 1
box.hidden = !box.hidden;
// способ 2
box.toggleAttribute("hidden");
Оба способа управляют одним и тем же атрибутом hidden в разметке - результат не отличается.
Частые ошибки с атрибутом hidden
Часть ошибок с hidden связана не с синтаксисом, а с тем, что скрытие не такое полное, как кажется на первый взгляд.
| Ошибка | Что происходит | Как исправить |
|---|---|---|
| Скрипты и формы внутри hidden-блока считают неактивными | Дочерний <script> внутри элемента с hidden всё равно выполняется, а поле формы продолжает участвовать в отправке данных - hidden скрывает только отображение | Не полагаться на hidden как на способ отключить логику - для этого нужны отдельные проверки в коде |
| hidden используют, чтобы спрятать что-то только визуально, оставив доступным скринридеру | hidden убирает элемент целиком и от скринридера тоже - исключения для него нет | Для «спрятано только от глаз» нужны другие приёмы, а не hidden |
| CSS-правило с display случайно перебивает hidden | Из-за специфичности или более позднего порядка правило вроде .card{display:flex} включает отображение, хотя hidden в разметке остался | Проверять, не конфликтует ли hidden с существующими display-правилами, или усиливать hidden через !important в сбросе стилей |
hidden путают с input type="hidden" | Это разные механизмы: один прячет любой тег целиком, другой - тип поля формы для служебных данных | Использовать hidden для скрытия элементов, а type="hidden" - для данных формы |
| hidden="until-found" ожидают раскрыть обычным кликом, без ссылки или поиска | Снятие атрибута у until-found происходит только через переход по якорю на id элемента или через поиск по странице - кнопкой без привязки к id или якорной ссылке это не сработает | Использовать якорную ссылку на id элемента или полагаться на поиск по странице (Ctrl+F) |
Шпаргалка по атрибуту hidden
| Правило | Что запомнить |
|---|---|
| Где работает | На любом теге (глобальный атрибут), значение не обязательно |
| Допустимые значения | Пусто, hidden, любое другое (кроме until-found) - все дают одинаковое скрытое состояние |
| Эффект по умолчанию | Элемент не занимает места на странице и недоступен скринридеру |
| Переопределение из CSS | display в стилях побеждает hidden, атрибут при этом остаётся в разметке |
hidden="until-found" | Скрыт визуально, но находится через Ctrl+F или переход по якорной ссылке; коробка (поля, рамка, фон) остаётся |
| Событие при раскрытии until-found | beforematch - срабатывает перед тем, как браузер сам снимет атрибут |
| Скрипты/формы внутри hidden | Продолжают выполняться и участвовать в отправке данных |
input type="hidden" | Другой механизм - служебное поле формы, не связано с атрибутом hidden |
aria-hidden="true" | Прячет только от скринридера, элемент остаётся виден на экране |
| Переключение из JS | element.hidden или toggleAttribute("hidden") |