Menu

z-index в CSS: порядок наложения и контекст наложения

z-index решает, какой из перекрывающихся элементов рисуется сверху. Разберем, на какие элементы он действует, как контексты наложения группируют элементы так, что z-index 9999 все равно проигрывает, что создает контекст наложения и как починить неработающий z-index.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Что делает z-index

Когда элементы перекрываются, z-index решает, какой из них рисуется спереди. Побеждает большее число. Он действует на позиционированные элементы (любой position, кроме static) и на flex- и grid-элементы:

Без z-index более поздние элементы в HTML рисуются поверх более ранних, поэтому C закрыл бы B, а B закрыл бы A. Значения z-index меняют это: A спереди, затем C, затем B.

Значения

ЗначениеСмысл
auto (по умолчанию)На уровне 0 вместе с соседями, контекст наложения не создает
0Уровень 0, но создает контекст наложения
Положительное целоеПеред меньшими значениями
Отрицательное целоеЗа уровнем 0 и за содержимым родителя, если родитель образует контекст наложения

Допустимы только целые числа: z-index: 1.5 игнорируется.

Почему z-index 9999 может проиграть: контексты наложения

Значения z-index не сравниваются по всей странице. Элементы группируются в контексты наложения, и z-index упорядочивает только элементы внутри одного контекста. Сам контекст затем размещается как один слой по z-index элемента, который его создал.

Ниже у синего выпадающего меню z-index: 9999, но оно находится внутри шапки с z-index: 1. У зеленого баннера, соседа этой шапки, z-index: 2. Весь слой шапки, вместе с меню, оказывается под баннером:

Нажмите кнопку. С z-index: auto шапка больше не образует контекст наложения, поэтому 9999 меню сравнивается с 2 баннера напрямую, и меню выходит вперед. Поднять меню до 99999 не помогло бы никогда.

Что создает контекст наложения

Любое из этого превращает элемент в собственный контекст наложения и запирает z-index всего, что внутри:

СвойствоУсловие
position: relative или absoluteС z-index, отличным от auto
position: fixed или stickyВсегда
Flex- или grid-элементС z-index, отличным от auto
opacityМеньше 1
transform, scale, rotate, translateЛюбое значение, кроме none
filter, backdrop-filterЛюбое значение, кроме none
isolationisolate
mix-blend-modeЛюбое значение, кроме normal
will-changeС указанием любого из свойств выше
containlayout или paint (а также strict, content)

Неожиданнее всего opacity и transform: если добавить родителю затухание или анимацию при наведении, его выпадающее меню вдруг может оказаться под следующей секцией.

z-index: 10 у подсказки должен ставить ее над следующей колонкой. Но opacity: 0.99 делает первую колонку контекстом наложения с z-index auto (уровень 0), а вторая колонка идет в HTML позже на том же уровне, поэтому она рисуется поверх всей первой колонки вместе с подсказкой. Удалите строку с opacity, и подсказка снова впереди.

Отрицательный z-index

Отрицательный z-index ставит элемент за его соседей. Если родитель не образует контекст наложения, элемент может уйти даже за фон родителя, и это частый сюрприз. isolation: isolate у родителя создает контекст без других визуальных эффектов и удерживает отрицательный дочерний элемент внутри:

Без isolation янтарная рамка уходит за собственный серый фон кнопки, и виден только ее край. С isolation: isolate рамка остается внутри контекста наложения кнопки: над ее фоном, под ее текстом.

Шкала z-index

Выберите для всего сайта несколько именованных слоев вместо гонки чисел:

:root {
  --z-dropdown: 10;
  --z-sticky: 20;
  --z-overlay: 30;
  --z-modal: 40;
  --z-toast: 50;
}
.modal { position: fixed; z-index: var(--z-modal); }

Большинство ошибок наложения это ошибки контекстов, а не чисел, поэтому небольшая шкала плюс isolation: isolate у компонентов, которые используют z-index внутри себя, решает многое. z-index нужно позиционирование; оно разобрано на странице про position.

Частые ошибки

  • z-index у статичного элемента. Добавьте position: relative (или сделайте его flex- или grid-элементом).
  • Гонка до 9999. Если родитель образует контекст ниже конкурента, никакое значение у дочернего элемента не победит. Найдите этот контекст.
  • Новые opacity, transform или filter у родителя, которые вдруг запирают его выпадающее меню.
  • Дробные значения. z-index: 1.5 невалидно.
  • Ожидание, что z-index: 0 и auto ведут себя одинаково. 0 создает контекст наложения, auto нет.
  • Модальные окна внутри глубоко вложенных компонентов. Отрисовывайте их ближе к концу <body> (или используйте верхний слой элемента <dialog>), чтобы их не запер контекст ни одного предка.

Часто задаваемые вопросы

Что делает z-index?

Задает порядок наложения перекрывающихся элементов: большее значение рисуется перед меньшим в пределах одного контекста наложения. По умолчанию auto, а значения это целые числа, в том числе отрицательные.

Почему не работает z-index?

Либо элемент не позиционирован (z-index нужен position, отличный от static, или элемент должен быть flex- или grid-потомком), либо он находится внутри родителя, который образует контекст наложения с более низким порядком. Дочерний элемент никогда не поднимется над элементом, ниже которого стоит его контекст наложения, каким бы ни был его собственный z-index.

Что такое контекст наложения?

Группа элементов, которые накладываются вместе как один слой. Внутри нее дочерние элементы упорядочены по своему z-index; снаружи всю группу размещает z-index элемента, который ее создал.

Что создает контекст наложения?

Среди прочего: корневой элемент, позиционированный элемент с z-index, отличным от auto, position: fixed или sticky, flex- или grid-потомок с z-index, opacity меньше 1, transform, filter, isolation: isolate и will-change для этих свойств.

Работает ли z-index без position?

У обычных блочных и строчных элементов нет: position: static его игнорирует. У flex- и grid-элементов он работает без всякого position.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ