Кратко
СкопированоКонтекст наложения — набор правил, на основании которых браузер решает, какой элемент на странице будет выше или ниже других. Условно, если представлять элементы как колоду карт, то правила формирования контекста наложения тасуют колоду. Это одна из основных концепций CSS.
Всё по порядку
СкопированоБраузер при отрисовке страницы идёт сверху вниз по HTML-разметке и рисует блоки один за другим в том же порядке, в котором они расположены. Мы видим и воспринимаем это как плоский лист, на котором один за другим выстраиваются элементы. Но браузер хитрый и на самом деле он располагает элементы не только по осям x и y, но ещё и по оси z. По глубине, так сказать.
Вы можете резонно заметить «Монитор же плоский! Какая ещё глубина?». Ваша правда. Но браузеру важно учитывать глубину элементов, чтобы при необходимости правильно наложить их друг на друга.
В стандартной ситуации тот элемент, который находится ниже в HTML-разметке будет ближе к пользователю. Давайте посмотрим на примере. Пусть в нашей разметке будет два блока:
<div class="block first"></div><div class="block second"></div>
<div class="block first"></div> <div class="block second"></div>
И для наглядности мы сдвинем второй блок чуть вверх и вправо:
.second { margin-top: -50px; margin-left: 50px;}
.second { margin-top: -50px; margin-left: 50px; }
В результате явно видно, что второй блок перекрывает собою первый, а значит находится выше в стопке элементов по оси z.
z-index
СкопированоНо мы можем не подчиняться стандартным правилам браузера и устанавливать свой порядок наложения элементов друг на друга. Для этого понадобится свойство z
.
Перемешаем элементы в нашем примере. Для наглядности добавим третий блок:
<div class="block first"></div><div class="block second"></div><div class="block third"></div>
<div class="block first"></div> <div class="block second"></div> <div class="block third"></div>
И пусть последний блок и первый блоки перекрывают второй блок. Для этого достаточно добавить позиционирование и z
для первого, а последний и так выше, просто по порядку следования:
.first { position: relative; z-index: 1;}
.first { position: relative; z-index: 1; }
Для большинства стандартных случаев этих знаний достаточно. Но случаются ситуации посложнее. Пойдём глубже и поговорим про контекст наложения.
Контекст наложения
СкопированоНа самом деле уже в предыдущих примерах мы с вами поработали с контекстом наложения. Просто не знали об этом 😅
Контекст наложения — это концепция трёхмерного расположения элементов по оси z относительно пользователя, смотрящего на экран.
Самый базовый контекст наложения, существующий на любой странице формируется корневым элементом <html>
. Все элементы внутри этого контекста сортируются и располагаются с оглядкой друг на друга.
Но мы можем создавать контексты наложения не только на странице целиком, но и в каждом отдельном блоке. Тогда вложенные в него дочерние блоки будут сортироваться и располагаться уже по правилам этого нового, родительского контекста наложения.
Новый контекст наложения формируется если:
- это корневой элемент (
<html>
), - элемент позиционирован абсолютно (
position
) или относительно (: absolute position
) со свойством: relative z
, значение которого не- index auto
, - флекс-элемент со свойством
z
, значение которого не- index auto
и чей родительский элемент имеет свойствоdisplay
или: flex display
,: inline - flex - элементу задано свойство
opacity
со значением меньше1
, - элементу задано свойство
transform
со значением неnone
, - элементу задано свойство
mix
со значением не- blend - mode normal
, - элементу задано свойство
filter
со значением неnone
, - элементу задано свойство
isolation
со значениемisolate
, - элемент с
position
,: fixed - элементу задано свойство
will
или аналогичный атрибут,- change - элементу задано свойство
-webkit
со значением- overflow - scrolling touch
.
Остальные элементы, не создающие собственный контекст наложения, используют родительский контекст.
Обычно достаточно запомнить первые три сценария и чуть-чуть помнить про следующие два. Если браузер рисует что-то, чего вы не ожидали, можно всегда вернуться и подсмотреть остальные.
Разные колоды карт
СкопированоСтоит запомнить одну важную вещь, связанную с контекстом наложения: элементы могут сортироваться находясь на одном уровне внутри контекста наложения. Элементы внутри блока никогда не могут быть выше или ниже своего родителя.
Пусть у нас будет два блока. Внутри первого будут три дочерних блока:
<div class="block parent"> <div class="child brown"></div> <div class="child red"></div> <div class="child yellow"></div></div><div class="block no-parent"></div>
<div class="block parent"> <div class="child brown"></div> <div class="child red"></div> <div class="child yellow"></div> </div> <div class="block no-parent"></div>
Пусть оба блока будут не статично спозиционированы и с z
, чтобы создать внутри каждого свой контекст наложения:
.block { position: relative; z-index: 1;}
.block { position: relative; z-index: 1; }
А теперь попробуем сделать так, чтобы жёлтый блок был поверх розового:
.yellow { position: relative; z-index: 9999999;}
.yellow { position: relative; z-index: 9999999; }
Результат огорчает, жёлтый блок по-прежнему под розовым. Потому что z
влияет на сортировку элементов только внутри блока .parent
и его контекста наложения.
Порядок наложения
СкопированоВнутри каждого контекста наложения существует свой порядок отрисовки элементов и их компонентов. Ниже перечисление идёт от самого нижнего слоя, до самого верхнего:
- Фон (
background
) и рамки элемента (border
); - Позиционированные элементы (включая потомков), у которых значение свойства
z
меньше 0;- index - Элементы без контекста наложения с
display
;: block - Элементы со свойством
float
; - Элементы с
display
;: inline - Элементы (включая потомков) с
z
или- index : auto z
, а также элементы с- index : 0 opacity
меньше 1; - Элементы (включая потомков) с
z
больше 0.- index
Согласно этому порядку, элемент с отрицательным значением z
никогда не будет ниже фона или рамки родительского элемента.
Оставив только один блок с потомками из примера выше. Попробуем жёлтый спрятать под синий фон родителя или под родительскую рамку. Чуть сместим его в бок для наглядности:
.yellow { z-index: -9999999; margin-left: 90px;}
.yellow { z-index: -9999999; margin-left: 90px; }
Он станет ниже своих соседей, но не уйдёт под синий фон родителя и останется поверх рамки родителя.