Что никто вам не расскажет о z-index
Проблема z-index в том, что мало кто четко понимает как он на самом деле работает. В нём нет ничего сложного, но если вы никогда не уделяли времени чтению его спецификации, почти наверняка вы не в курсе важных аспектов.
Не верите мне? Посмотрим, сможете ли вы решить следующую проблему.
Проблема
В представленном ниже HTML у нас есть три элемента <div>, каждый из которых содержит элемент <span>. Каждый элемент, в свою очередь, имеет цвет фона – красный, зелёный и синий соответственно. Также каждый элемент <span> имеет абсолютное позиционирование где-то около верхнего левого угла документа и немного перекрывает другие элементы <span>, чтобы было видно какой элемент находится поверх другого. Для первого элемента <span> значение свойства z-index равно 1, а для других двух это свойство не задано.
Вот как выглядят HTML и основные стили CSS. Ниже я также добавил визуальное демо с Codepen с полным CSS.
<div> <span class="red">Red</span> </div> <div> <span class="green">Green</span> </div> <div> <span class="blue">Blue</span> </div>
.red, .green, .blue {
position: absolute;
}
.red {
background: red;
z-index: 1;
}
.green {
background: green;
}
.blue {
background: blue;
}
Задача состоит в следующем: попробуйте расположить красный элемент <span> за синим и зелёным элементами, не нарушая следующие условия:
- Нельзя изменять и дописывать HTML-разметку
- Нельзя дописывать/менять свойство
z-indexу элементов - Нельзя дописывать/менять свойство
positionу элементов
Вы должны получить следующую картину:
Внимание! Не нажимайте на вкладку с CSS, чтобы не подсмотреть ответ.
Решение
Ответом является добавление непрозрачности к первому элементу <div> (родителю красного элемента <span>) со значением, чуть меньшим, чем 1. Вот CSS, который был добавлен к примеру выше:
div:first-child {
opacity: .99;
}Если вы сейчас в шоке ломаете себе голову и не можете поверить, что прозрачность будет влиять на порядок наложения элементов, добро пожаловать в клуб. Я был потрясён точно также, когда я впервые наткнулся на эту ситуацию.
Надеюсь, остальная часть статьи немного прояснит ситуацию.
Порядок наложения
Z-index кажется таким простым: элементы с более высоким значением должны находиться выше элементов с более низким значением, верно? На самом деле, нет. Это часть проблемы с z-index. С первого взгляда он кажется простым и большинство разработчиков не тратят время на изучение правил его применения.
Каждый элемент в HTML-документе может находиться как выше, так и ниже других элементов. Это называется порядком наложения. Правила этого наложения довольно чётко определены в спецификации, но, как я уже говорил, большинство разработчиков не полностью их понимают.
Когда свойства z-index и position не определены, правила очень просты: порядок наложения точно такой же, как и порядок появления в HTML, в основном. (OК, на самом деле всё немного сложнее, но пока вы не используете отрицательные значения свойства margin для перекрытия строчных элементов, вы, вероятнее всего, не столкнетесь с крайними случаями).
Если говорить о свойстве position, то любые позиционированные элементы (и их потомки) отображаются выше любых непозиционированных элементов. (Говоря “позиционированный” элемент, имеется ввиду, что у элемента задано свойство position, отличное от static – relative, 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 предсказуемым. Давайте начнём с того, что нарушим порядок на отдельных контекстах наложения.
Порядок наложения в пределах одного контекста наложения
Вот основные правила, чтобы определить порядок наложения в одном контексте наложения (от низа к верху):
- Корневой элемент контекста наложения
- Позиционированные элементы (и их потомки) с отрицательными значениями свойства
z-index(бОльшие значения “укладываются” выше меньших значений; элементы с одинаковыми значениями располагаются в том же порядке, что и в HTML) - Непозиционированные элементы (располагаются в том же порядке, что и в HTML)
- Позиционированные элементы (и их потомки) со значением
autoсвойстваz-index(располагаются в том же порядке, что и в HTML) - Позиционированные элементы (и их потомки) с положительными значениями свойства
z-index(бОльшие значения “укладываются” выше меньших значений; элементы с одинаковыми значениями располагаются в том же порядке, что и в HTML)
Примечание: позиционированные элементы с отрицательными значениями
z-indexбудут находиться первыми в контексте наложения, что означает, что они будут отображаться позади всех остальных элементов. Из-за этого у элемента появляется возможность находиться позади своего родителя, что обычно невозможно. Это будет работать только тогда, когда родитель элемента имеет тот же контекст наложения и не является его корневым элементом.
Глобальный порядок наложения
Имея чёткое понимание того, как/когда формируются новые контексты наложения, а также представление о порядке наложения в контексте наложения, выяснить, где конкретный элемент появится в глобальном порядке наложения не так уж и трудно.
Ключом к тому, чтобы не споткнуться на этом пути, является возможность определять, когда новые контексты наложения формируются. Если вы устанавливаете элементу значение z-index в миллиард и он не перемещается выше в порядке наложения, посмотрите на его генеалогическое дерево на предмет того, формирует ли любой из его родителей контекст наложения. Если образуют, то ваш z-index в миллиард не даст никакой пользы.
Заключение
Возвращаясь к исходной задаче, я воссоздал его HTML-структуру, добавив комментарии внутри каждого тега, которые показывают его место в порядке наложения. Это порядок при исходных правилах CSS.
<div><!-- 1 --> <span class="red"><!-- 6 --></span> </div> <div><!-- 2 --> <span class="green"><!-- 4 --><span> </div> <div><!-- 3 --> <span class="blue"><!-- 5 --></span> </div>
Когда мы добавим правило opacity к первому элементу <div>, порядок наложения поменяется:
<div><!-- 1 --> <span class="red"><!-- 1.1 --></span> </div> <div><!-- 2 --> <span class="green"><!-- 4 --><span> </div> <div><!-- 3 --> <span class="blue"><!-- 5 --></span> </div>
span.red был 6, а стал 1.1. Я использовал точку, чтобы показать, что сформировался новый контекст наложения и span.red теперь является первым элементам в новом контексте.
Надеюсь, что вам теперь понятно, почему красный блок оказался позади всех остальных. Исходный пример содержал всего два контекста наложения, корневой и ещё один, сформированный элементом span.red. Добавив непрозрачность родителю элемента span.red, мы создали третий контекст наложения и, как следствие, значение z-index элемента span.red теперь действует в рамках нового контекста. Из-за того, что первый элемент <div> (тот, к которому мы применили непрозрачность) и его родственные элементы не позиционированы и не имеют установленного значения свойства z-index, их порядок наложения определяется порядком в HTML, что означает, что первый элемент <div> и все элементы в его контексте наложения располагаются позади второго и третьего элемента <div>.
Источник
