Что такое z-index?

Наши мониторы — это двумерные плоские поверхности с кучей пикселей. Но в вебе есть и третье измерение. Например, каждый из нас видел, как модальное окно всплывает «над» остальным контентом на первый план.

Представьте, что экран — это портал в трехмерный мир браузера. Визуализируем это пространство как комнату. Дальняя от нас стена называется «холст» (canvas).

Самые близкие к холсту пиксели (самые удаленные от нас) браузер рисует первыми. Каждый новый слой отображается поверх уже окрашенного.

Свойство z-index определяет порядок отображения блоков в этой иллюзорной трехмерности. По умолчанию все элементы имеют нулевой индекс и отрисовываются в том порядке, в котором находятся в DOM. Мы можем приближать их к себе или отдалять.

В спецификации CSS Position & Layout есть вот такая схема:

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

Прежде всего, индекс будет работать только на спозиционированном элементе (свойство position отличается от static). Для элемента, находящегося в обычном потоке, эффекта не будет.

Введение в контекст наложения

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

Базовый контекст наложения создается узлом html. По умолчанию к нему принадлежат и все остальные элементы в документе. Однако любой из них также может стать корневым узлом локального контекста.

Создать новый контекст можно несколькими способами:

  • установить абсолютное или относительное позиционирование, а также любой z-index кроме auto;
  • установить фиксированное позиционирование (fixed или sticky);
  • установить прозрачность меньше 1;
  • использовать свойства transform или will-change.

Полный список способов создания контекстов можно найти на MDN.

Рассмотрим три HTML-дерева. Нижняя часть — это корневой узел, а потомки уложены сверху. Предположим, что все три корня находятся прямо внутри body.

Это будет выглядеть примерно так:

See the Pen by Benjamin Johnson (@benjaminj6) on CodePen.

Не ожидали?

Прежде всего, почему blue-child-2 находится внизу? Ведь его z-index равен миллиону, он должен самым верхним, не так ли?

Почему green-child-1 наверху, хотя его z-index всего 2? Разве больший индекс не должен перекрывать меньший?

Начнем с green-child-1. Его родитель — green-parent — имеет z-index: 999, поэтому мы предполагаем, что он поднимется на самый верх. Но z-index не влияет на элементы с position: static. Это означает, что green-child-1 является частью корневого контекста наложения, в котором, кроме него, есть еще red-parent и blue-parent. Он имеет более высокий z-index, чем они, поэтому находится выше.

Красный и синий корневые блоки создают собственные локальные контексты наложения. Почему blue-child-2 находится ниже, чем red-parent, несмотря на больший z-index? Дело в том, что это свойство управляет положением слоя только в локальном контексте. blue-child-2, безусловно, будет выше всех дочерних элементов blue-parent. Но контекст red-parent выше, чем контекст blue-parent, поэтому все красные потомки всегда будут выше синих.

Чтобы поднять blue-child-2 выше red-parent придется изменить структуру HTML и извлечь его из локального контекста наложения в корневой (или в другой локальный, который будет выше красного). Но помните, что такие изменения в больших проектах могут привести к непредвиденным последствиям.

Многие библиотеки компонентов используют интерфейс с большим количеством слоев (всплывающие подсказки, модальные окна), добавляя их к тегу body, а не внутрь самого компонента. Это позволяет обойти подводные камни стека наложения и гарантирует, что нужные элементы всегда будут на самом верху.

Вывод

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

  1. z-index работает только на позиционированных элементах;
  2. z-index работает внутри текущего контекста наложения.

Зная об этих тонкостях вы легко сможете создавать грамотные многоуровневые интерфейсы.

2 комментария

  • baturiya
    baturiya
    18/09/2018, 11:11
    Вот подскажите мне на резал кучу картинок, загнал в размер.ю сделал по ним переходы - тоесть использую, как ссылки, в CSS задал z-index для ссылок и для псевдокласса, все вроде работает, только вот что -две ссылки мне надо оставить отдельно, тоесть чтобы не срабатывал z-index, как мне это сделать?
    • Furry_web
      Furry_web
      20/09/2018, 05:59
      Задать этим ссылкам position: static, в этом случае z-index не будет работать.

Оставить комментарий

*Доступные HTML-теги: a, abbr, blockquote, code, pre, del, i, em, strong, b, strike
*Не будет опубликован