Почти два года назад вышла статья «What no one told you about z-index» (и её перевод на Хабре «То, что вам никто не говорил о z-index»), авторы которой рассказывают о малоизвестной (76% проголосовавших пользователей Хабра слышат об этом впервые), но документированной возможности создания нового контекста наложения указавopacity
меньше единицы.
Но несмотря на название статьи, авторы не рассказали вам ещё кое о чём.
Элементы с общими родителями, перемещающиеся на передний или задний план вместе известны как контекст наложения. Понимание контекста наложения является ключом к пониманию
z-index
и порядка наложения элементов.Каждый контекст наложения имеет свой корневой элемент в HTML структуре. В момент формирования нового контекста на элементе, все дочерние элементы так же попадают в этот контекст и занимают своё место в порядке наложения. Если элемент располагается в самом низу одного контекста наложения, то никаким мыслимым и немыслимым образом не получится отобразить его над другим элементом в соседнем контексте наложения, располагающимся выше по иерархии, даже с установленным
z-index
равным миллиону.
— Из статьи «То, что вам никто не говорил о z-index». Для понимания темы настоятельно рекомендую к ознакомлению либо её, либо классический труд на MDN.
Новый контекст наложения формируется в случаях:
- Корневой элемент (
<html>
) всегда содержит корневой контекст наложения. Любой элемент на странице, не участвующий в локальном контексте наложения (сформированном любым из последующих вариантов), участвует в корневом контексте наложения. - Элемент с
position
отличным отstatic
и значениемz-index
отличным отauto
. Кроме одного исключения дляposition: fixed
, но я это вынес в отдельный пункт. - Элемент имеет значение
opacity
меньше, чем1
. - Flex-элемент со значением
z-index
отличным отauto
, даже в случаеposition: static
. - Трансформированные элементы: значение
transform
отличное отnone
;transform-style
со значениемpreserve-3d
; иperspective
со значением отличным отnone
. - CSS Regions: установление значения
flow-from
отличное отnone
для элемента сcontent
отличным отnormal
. - Paged Media: каждый Page-Margin Box устанавливает собственный контекст наложения.
- И наконец пункт, ради которого я и пишу эту статью — мобильные браузеры на основе WebKit, а также Google Chrome 22+ всегда создают новый контекст наложения для
position: fixed
-элементов, даже сz-index: auto
!
Рассмотрим последний сценарий более подробно. Он единственный из всего списка не описан стандартами W3C.
Взгляните на пример.
На этой странице две похожие DOM-структуры:
<div class="container">
<div class="green"></div>
<div class="pink"></div>
<div class="fixed">
<div class="orange"></div>
</div>
</div>
Со стилями:
.container { position:absolute; }
.green { position:relative; z-index: 1; }
.pink { position:relative: z-index: 3; }
.fixed { position:fixed; }
.orange { position:relative; z-index: 2; }
Единственное отличие — во втором варианте добавлен opacity: .99
для .fixed
. Поскольку в Google Chrome (начиная с 22 версии), а также в мобильных WebKit-браузерах фиксировано-позиционированные элементы создают новый контекст наложения (так же как и элементы с opacity: .99
) — в этих браузерах обе фигуры будут идентичны.
В свою очередь остальные браузеры покажут иную картину.
Так получилось потому, что значение z-index
нашего .fixed
-элемента равно auto
(что не создаёт контекста наложения в левой фигуре). .orange
оказался в контексте наложения .container
и встал согласно своему z-index
(после .green
, но перед .pink
).
Зачем Google Chrome пошёл против стандартов?
К слову, первыми так стали делать Apple в Safari на iOS 5+, а также основные браузеры для Android (кроме Firefox).
Чтобы понять зачем, стоило покопаться в архиве [email protected] и найти письмо Джеймса Робинсона из Google, в котором он подробно излагает суть проблемы, приводит пример (который я использовал в статье) и рассказывает, что новый контекст наложения для position: fixed
-элементов в мобильных браузерах создаётся для оптимизации скролла и улучшения user experience (хотя я так и не могу понять, о какой конкретно оптимизации идёт речь и буду признателен если кто-нибудь сможет мне объяснить).
Таким образом в Google Chrome просто сделали одинаковое поведение фиксированных элементов на desktop и mobile, проигнорировав рекомендации W3C. Хотя с их стороны были предложения принять такое поведениеposition: fixed
в стандарт, но консорциум пока не проявил интереса к этим изменениям.
Как обстоят дела на текущий момент?
Подводя итоги, новый контекст наложения для position: fixed
формируется в следующих браузерах:
- Мобильные браузеры на основе WebKit
- Google Chrome 22+ (и его производные)
- Apple Safari 6.1+ (Desktop)
- Opera Blink (а также мобильные версии)
Mozilla Firefox не создают контекст наложения в такой ситуации и не считают это необходимым ни для Desktop, ни для Mobile, поскольку не испытывают проблем с оптимизацией скролла.
Internet Explorer (проверил версии 10 и 11) также не формируют контекст наложения для position: fixed
, но комментариев от представителей Microsoft я не нашёл и непонятна их позиция в этом вопросе. У меня не было возможности проверить поведение на Windows Phone и узнать, соответствует ли оно поведению на Desktop. Буду признателен, если кто-то поделится результатом эксперимента.
В любом случае W3C даёт лишь рекомендации, а каждый вендор решает сам для себя следовать им или нет. Нам же, простым разработчикам, остаётся лишь учитывать подобные нюансы в своих веб-приложениях (хорошо, что одна корпорация с небезызвестным продуктом закаляла нас годами).