То, что вам никто не говорил о z-index в статье «То, что вам никто не говорил о z-index»

9e935143188e60601d3ff89cc52f28d2
Почти два года назад вышла статья «What no one told you about z-index» (и её перевод на Хабре «То, что вам никто не говорил о z-index»), авторы которой рассказывают о малоизвестной (76% проголосовавших пользователей Хабра слышат об этом впервые), но документированной возможности создания нового контекста наложения указавopacity меньше единицы.

Но несмотря на название статьи, авторы не рассказали вам ещё кое о чём.

Предполагается, что вы знакомы с понятием контекста наложения (англ. stacking context).

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

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

— Из статьи «То, что вам никто не говорил о z-index». Для понимания темы настоятельно рекомендую к ознакомлению либо её, либо классический труд на MDN.


Новый контекст наложения формируется в случаях:


Рассмотрим последний сценарий более подробно. Он единственный из всего списка не описан стандартами 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) — в этих браузерах обе фигуры будут идентичны.
bc509a33953ff0cd7faacb3e9bae73b1

В свою очередь остальные браузеры покажут иную картину.
9e935143188e60601d3ff89cc52f28d21

Так получилось потому, что значение 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 формируется в следующих браузерах:


Mozilla Firefox не создают контекст наложения в такой ситуации и не считают это необходимым ни для Desktop, ни для Mobile, поскольку не испытывают проблем с оптимизацией скролла.

Internet Explorer (проверил версии 10 и 11) также не формируют контекст наложения для position: fixed, но комментариев от представителей Microsoft я не нашёл и непонятна их позиция в этом вопросе. У меня не было возможности проверить поведение на Windows Phone и узнать, соответствует ли оно поведению на Desktop. Буду признателен, если кто-то поделится результатом эксперимента.

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