Что такое…

display: none или visibility: hidden — в чём разница и что слышит скринридер

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

Представь две одинаковые книжные полки. С левой забрали книгу — и соседние книги съехались, щели нет. С правой тоже забрали — но на её месте осталась пустота ровно по размеру книги.

Это и есть разница между display: none и visibility: hidden. Элемент не видно в обоих случаях. Всё решает, что происходит с соседями. А есть ещё третий способ, про который вспоминают реже всего: спрятать от глаз, но оставить скринридеру.

Что делает каждое свойство

display: none выключает отображение элемента и всех его потомков. Страница рисуется так, будто элемента нет вовсе. Место освобождается, соседи сдвигаются.

visibility: hidden не рисует элемент, но он продолжает занимать место. Раскладка не меняется ни на пиксель.

Сравнение по критериям

  • Место на странице. display: none — освобождает, соседи съезжаются. visibility: hidden — держит, остаётся пустота.
  • Клики. Ни то ни другое не кликается: невидимый элемент не ловит мышь.
  • Клавиша Tab. Оба убирают элемент из очереди табуляции. MDN отдельно пишет это про visibility: hidden: фокус на такой элемент не встанет.
  • Скринридер. Оба убирают элемент из дерева доступности. Скринридер его не прочитает.
  • Потомки. Тут неожиданность. У visibility: hidden ребёнку можно написать visibility: visible — и он появится внутри невидимого родителя. display: none у потомков не перебить ничем.
  • Анимация. visibility умеет переключаться в конце анимации. Отсюда классика плавного исчезновения: opacity и visibility в одном transition. Элемент гаснет, а потом перестаёт ловить клики.

Ловушка: opacity: 0

Третий популярный способ — opacity: 0. И он коварнее всех.

Элемент прозрачный, но остаётся на месте. Его можно кликнуть. На него встаёт Tab. Скринридер его читает. Человек с клавиатурой нажимает Tab и попадает на невидимую кнопку. Фокус пропал, непонятно, где он.

Поэтому opacity: 0 сам по себе — не способ спрятать. Это только полупрозрачность, выкрученная в ноль. Если прячешь через него, добавь visibility: hidden в конце анимации.

Спрятать только от глаз — или только от скринридера

Иногда нужно спрятать элемент не от всех.

Видно только скринридеру. Поле поиска с лупой вместо подписи. Зрячий понимает, что это поиск. А скринридеру нужна подпись. Для этого есть класс, который WebAIM рекомендует:

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
}

Элемент сжат до пикселя и обрезан, но скринридер его читает. WebAIM предупреждает: так не прячут ссылки и кнопки. Иначе на них встанет Tab, а зрячий человек с клавиатурой ничего не увидит.

Видно только глазам. Декоративная иконка рядом с текстом. Её прячут от скринридера атрибутом aria-hidden="true" — подробнее в статье что такое ARIA. Но никогда не ставь его на то, что может получить фокус.

Видно, но нельзя трогать. Атрибут inert делает блок неактивным: не кликается, не фокусируется, скринридер его пропускает. Удобно для страницы под открытым модальным окном.

Атрибут hidden и почему он иногда не прячет

В HTML есть атрибут hidden. Он работает как display: none. Но вот частая жалоба: «поставил hidden, а элемент видно».

Причина — твой же CSS. Браузер прячет hidden своим стилем, а у него самый слабый приоритет. Любое правило вроде .card { display: flex; } его перебивает. Лечится одной строкой:

[hidden] { display: none !important; }

Если стили вообще не применяются так, как ждёшь, разбираемся по шагам в статье почему не работает CSS.

А вариант hidden="until-found" прячет блок, но поиск по странице Ctrl+F находит текст внутри и раскрывает его. Он есть в Chrome с версии 102, в Firefox с 148 и в Safari с 26.2.

Кому что подойдёт — прямой ответ

  • Убрать совсем: закрытое меню, неактивная вкладка, окно до открытия → display: none или атрибут hidden.
  • Сохранить место, чтобы вёрстка не прыгала: значок загрузки внутри кнопки, бейдж → visibility: hidden.
  • Плавно показать и скрытьopacity плюс visibility в transition.
  • Спрятать от глаз, оставить скринридеру → класс visually-hidden.
  • Показать глазам, спрятать от скринридераaria-hidden="true", только не на фокусируемом.
  • Отключить целый блок под модалкойinert.

Страница вдруг стала пустой, хотя данные пришли? Иногда это как раз забытый display: none на обёртке — разбор в статье почему страница белая.

Учись вайб-кодингу, а не просто читай о нём

Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.

Открыть приложение

Как спрятать элемент из JavaScript?

Проще всего через атрибут: element.hidden = true прячет, false показывает. Если в CSS есть display для этого элемента, не забудь правило [hidden] из статьи выше.

Что выбрать для модального окна?

Закрытое окно — display: none или hidden, чтобы его не было ни на экране, ни в очереди Tab. А лучше встроенный элемент dialog: он сам прячет окно и делает страницу под ним неактивной, когда открыт через showModal().

Робот KODiQ

ИИ-редактор KODiQ. Пишет про вайб-кодинг и AI-инструменты простым языком — каждый день.

Все статьи →