Что никто вам не расскажет о z-index

Проблема z-index в том, что мало кто четко понимает как он на самом деле работает. В нём нет ничего сложного, но если вы никогда не уделяли времени чтению его спецификации, почти наверняка вы не в курсе важных аспектов.

Не верите мне? Посмотрим, сможете ли вы решить следующую проблему.

Проблема

В представленном ниже HTML у нас есть три элемента <div>, каждый из которых содержит элемент <span>. Каждый элемент, в свою очередь, имеет цвет фона – красный, зелёный и синий соответственно. Также каждый элемент <span> имеет абсолютное позиционирование где-то около верхнего левого угла документа и немного перекрывает другие элементы <span>, чтобы было видно какой элемент находится поверх другого. Для первого элемента <span> значение свойства z-index равно 1, а для других двух это свойство не задано.

Вот как выглядят HTML и основные стили CSS. Ниже я также добавил визуальное демо с Codepen с полным CSS.

Задача состоит в следующем: попробуйте расположить красный элемент <span> за синим и зелёным элементами, не нарушая следующие условия:

  • Нельзя изменять и дописывать HTML-разметку
  • Нельзя дописывать/менять свойство z-index у элементов
  • Нельзя дописывать/менять свойство position у элементов

Вы должны получить следующую картину:

Внимание! Не нажимайте на вкладку с CSS, чтобы не подсмотреть ответ.

Решение

Ответом является добавление непрозрачности к первому элементу <div> (родителю красного элемента <span>) со значением, чуть меньшим, чем 1. Вот CSS, который был добавлен к примеру выше:

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

Надеюсь, остальная часть статьи немного прояснит ситуацию.

Порядок наложения

Z-index кажется таким простым: элементы с более высоким значением должны находиться выше элементов с более низким значением, верно? На самом деле, нет. Это часть проблемы с z-index. С первого взгляда он кажется простым и большинство разработчиков не тратят время на изучение правил его применения.

Каждый элемент в HTML-документе может находиться как выше, так и ниже других элементов. Это называется порядком наложения. Правила этого наложения довольно чётко определены в спецификации, но, как я уже говорил, большинство разработчиков не полностью их понимают.

Когда свойства z-index и position не определены, правила очень просты: порядок наложения точно такой же, как и порядок появления в HTML, в основном. (OК, на самом деле всё немного сложнее, но пока вы не используете отрицательные значения свойства margin для перекрытия строчных элементов, вы, вероятнее всего, не столкнетесь с крайними случаями).

Если говорить о свойстве position, то любые позиционированные элементы (и их потомки) отображаются выше любых непозиционированных элементов. (Говоря “позиционированный” элемент, имеется ввиду, что у элемента задано свойство position, отличное от staticrelative, absolute или fixed.)

И, наконец, если участвует свойство z-index, то всё становится немного сложнее. Мы предполагаем, что элементы с более высоким значением z-index находятся выше элементов, у которых значение z-index ниже, а также любые элементы, у которых задано значение z-index, находятся выше элементов без z-index. Но всё не так просто. В первую очередь, z-index работает только у позиционированных элементов. Если вы попытаетесь задать свойство z-index элементу без позиционирования, ничего не произойдёт. Во-вторых, значения свойства z-index могут создать контексты наложения. Теперь, то, что в начале казалось простым, стало сложнее.

Контексты наложения

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

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

Новые контексты наложения могут быть сформированы на элементе в одном из трёх случаев:

  • Когда элемент является корневым элементом документа (элемент <html>)
  • Когда у элемента задано значение свойства position, отличное от static, и значение свойства z-index, отличное от auto
  • Когда элемент имеет значение свойства opacity меньше единицы

Первый и второй случай формирования контекста наложения имеют смысл и, как правило, понятны веб-разработчиками (даже если они не знают, как они называются).

Третий случай (непрозрачность) почти никогда не упоминался за пределами документов спецификаций W3C.

Определение позиции элемента в порядке наложения

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

Но для большинства задач и целей, общее представление о порядке может далеко пойти и помочь сохранить развитие CSS предсказуемым. Давайте начнём с того, что нарушим порядок на отдельных контекстах наложения.

Порядок наложения в пределах одного контекста наложения

Вот основные правила, чтобы определить порядок наложения в одном контексте наложения (от низа к верху):

  1. Корневой элемент контекста наложения
  2. Позиционированные элементы (и их потомки) с отрицательными значениями свойства z-index (бОльшие значения “укладываются” выше меньших значений; элементы с одинаковыми значениями располагаются в том же порядке, что и в HTML)
  3. Непозиционированные элементы (располагаются в том же порядке, что и в HTML)
  4. Позиционированные элементы (и их потомки) со значением auto свойства z-index (располагаются в том же порядке, что и в HTML)
  5. Позиционированные элементы (и их потомки) с положительными значениями свойства z-index (бОльшие значения “укладываются” выше меньших значений; элементы с одинаковыми значениями располагаются в том же порядке, что и в HTML)

Примечание: позиционированные элементы с отрицательными значениями z-index будут находиться первыми в контексте наложения, что означает, что они будут отображаться позади всех остальных элементов. Из-за этого у элемента появляется возможность находиться позади своего родителя, что обычно невозможно. Это будет работать только тогда, когда родитель элемента имеет тот же контекст наложения и не является его корневым элементом.

Глобальный порядок наложения

Имея чёткое понимание того, как/когда формируются новые контексты наложения, а также представление о порядке наложения в контексте наложения, выяснить, где конкретный элемент появится в глобальном порядке наложения не так уж и трудно.

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

Заключение

Возвращаясь к исходной задаче, я воссоздал его HTML-структуру, добавив комментарии внутри каждого тега, которые показывают его место в порядке наложения. Это порядок при исходных правилах CSS.

Когда мы добавим правило opacity к первому элементу <div>, порядок наложения поменяется:

span.red был 6, а стал 1.1. Я использовал точку, чтобы показать, что сформировался новый контекст наложения и span.red теперь является первым элементам в новом контексте.

Надеюсь, что вам теперь понятно, почему красный блок оказался позади всех остальных. Исходный пример содержал всего два контекста наложения, корневой и ещё один, сформированный элементом span.red. Добавив непрозрачность родителю элемента span.red, мы создали третий контекст наложения и, как следствие, значение z-index элемента span.red теперь действует в рамках нового контекста. Из-за того, что первый элемент <div> (тот, к которому мы применили непрозрачность) и его родственные элементы не позиционированы и не имеют установленного значения свойства z-index, их порядок наложения определяется порядком в HTML, что означает, что первый элемент <div> и все элементы в его контексте наложения располагаются позади второго и третьего элемента <div>.
Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.