Как работает CSS: создание слоев с помощью z-index

Как работает CSS: создание слоев с помощью z-index

От автора: сегодня будет разговор о том, как работает свойство z index CSS. Это третий пост в «Как работает CSS» — серия статей, где мы глубоко погружаемся в фундаментальные строительные блоки CSS, которые иногда похожи на черную магию. Независимо от того, как вы пишите CSS, всегда полезно знать, что «runtime» вашей таблицы стилей позволяет писать эффективный масштабируемый CSS.

Сегодня мы собираемся погрузиться в одну из тех частей черной магии CSS. Играя с z-index, мы часто бросаем все большие значения и смотрим, какие из них сработают. Но если мы снимем слои с z-index, и взглянем на правила, которые его определяют? Мы увидим, что это не так страшно, как мы думали.

Что такое Z-Index?

В конце концов, экраны, которые мы используем в браузере, представляют собой двумерные плоские поверхности с кучей пикселей. Но если вы в Интернете уже давно, скорее всего, вы часто имели «трехмерный» опыт. Например, вы можете щелкнуть по кнопке и открыть модальное окно или отобразить тултип «поверх» его кнопок.

Если вы предполагаете, что пользователь смотрит «на экран» и воображает, что экран представляет собой портал в трехмерный мир, вы можете начать визуализировать то, как выглядит это трехмерное пространство в браузере. Для начала, если бы мы визуализировали это пространство как комнату, то «стена», которая «находится дальше всего», называется «холст».

При рисовании пикселей на экране браузер гарантирует, что пиксели, которые ближе всего к холсту (или дальше от нас), будут нарисованы первее. Затем он постепенно продолжает рисовать элементы «ближе» к пользователю, перезаписывая ранее окрашенные пиксели.

Свойство z-index относится к порядку окраски элемента в этой иллюзии трехмерного браузера. По умолчанию все элементы имеют z-index 0, а браузер — в порядке DOM. Тем не менее, z—index фактически дает нам мелкозернистый контроль, когда элемент окрашивается. Назначая более высокий z-index мы можем заставить элемент окраситься таким образом, чтобы он был «ближе» к пользователю. Низкий (или отрицательный!) z-index позволяет нам рисовать элемент ближе к холсту.

Изучая CSS Position & Layout Spec, я нашел эту полезную диаграмму, чтобы визуализировать, как слои z-index смотрят на пользователя.

Как работает CSS: создание слоев с помощью z-index

Элементы с более высоким z-index кажутся «ближе» к пользователю

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

Первая оговорка, связанная с z-index заключается в том, что свойство должно быть на позиционированном элементе, чтобы вступить в силу. Это означает, что z-index может использоваться только для изменения порядка укладки, если вы установили position отличную от static. В любой ситуации, когда вы не задали position для элемента, z-index будет иметь нулевой эффект.

Представление контекста стека

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

Контекст стека включает узел HTML и все его дочерние элементы. Элемент HTML на корневом уровне контекста стека можно назвать корнем стека.

Контекст стека по умолчанию (или «контекст корневого стека») для документа имеет тег html как его «корень стека», и все элементы относятся к этому стековому контексту по умолчанию. Однако любой узел HTML также может быть корневым элементом «локального контекста стека».

Вот несколько способов, которыми можно назначить элемент как корень нового локального контекста стека:

position: absolute или position: relative вместе с любым z-index отличным от auto для элемента.

Использование position: fixed или position: sticky на элементе.

Установка opacity меньше 1 на элементе.

Использование transform или will-change в элементе.

В качестве примера давайте представим три дерева узлов HTML, визуализированных как три стека. На приведенной ниже диаграмме нижняя часть каждого стека является родительским узлом HTML, а дочерние элементы располагаются сверху (например, представление «вверх дном» дерева HTML). Давайте также притворимся, что каждый из этих элементов является прямым дочерним элементом тега body.

Как работает CSS: создание слоев с помощью z-index

Три стека элементов, родительские элементы находятся внизу

Если бы мы просмотрели эти элементы HTML в браузере, это выглядело бы примерно так:

Заметили что-нибудь странное со слоями?

Заметили что-нибудь интересное?

Во-первых, почему blue-child-2 ниже всего остального? Он имеет z-index в миллион, поэтому он должен быть сверху, правда?

Кроме того, почему green-child-1 появляется поверх всего, хотя у него z-index 2? Разве мы не говорили, что более высокие z-индексы «выигрывают» над более низкими z-индексами?

Начнем с green-child-1. Поскольку его родительский элемент — green-parent — имеет z-index 999 , мы ожидаем, что green-parent также будет выше всего остального. Но если вспомнить наше первое предупреждение об использовании z-index, это не повлияет на статически позиционированные элементы. Это означает, что green-child-1 является частью контекста корневого стека, и он измеряется против red-parent и blue-parent, единственных других двух элементов в корневом слое стека. Он имеет более высокий z-index чем тот, и он отображается сверху.

Понимание того, что red-parent и blue-parent каждый создают свои собственные локальные контексты стека, также помогает понять, почему blue-child-2 отображается ниже red-parent, хотя его z-index намного выше. Поскольку z-index управляет только позицией элемента в локальном контексте стека, blue-child-2 определенно будет выше всех детей blue-parent. Но у red-parent более высокий z-index, чем у blue-parent, все элементы внутри red-parent будут отображаться выше, чем blue-parent, независимо от их z-index.

Чтобы отобразить blue-child-2 над red-parent нам действительно пришлось бы изменить нашу структуру HTML, чтобы получить blue-child-2 из текущего локального контекста стека и в контекст корневого стека (или, по крайней мере, в стеке контекста, который выше red-parent).

Такие вещи часто могут быть сложными (даже вероломными) в более крупном приложении, особенно когда вы пытаетесь управлять такими вещами, как семантическая структура HTML, доступность и модульные архитектуры компонентов.

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

Заключение

Использование z-index может быть сложным в нескольких сценариях, но когда мы знаем правила того, как он работает внутри, мы обнаруживаем, что он действительно ведет себя вполне предсказуемо. Я бы предположил, что 99% путаницы вокруг z-index проистекает из непонимания двух подводных камней, которые мы обсуждали.

Быстро вспомним эти 2 предостережения.

z-index работает только с элементами, которые имеют значение position кроме static.

z-index применяется только к позиции элементов в контексте стека, к которому он принадлежит.

Надеюсь, что понимание внутреннего устройства z-index дает вам уверенность при создании многоуровневых UI с их различным ловушкам. Изучение z-index и слоев стека было очень полезно для меня для систематизации своего подхода к разработке UI – знать, какое число назначать намного лучше, чем просто бросать значения z-index.

Автор: Benjamin Johnson

Источник: https://blog.logrocket.com/

Редакция: Команда webformyself.