Stacking context — управление слоями интерфейса через CSS-контексты!
z-index не является глобальной системой нумерации слоёв страницы. Браузер строит дерево stacking context, где каждый контекст отрисовывается независимо. Значение z-index сравнивается только внутри текущего контекста и не позволяет дочернему элементу напрямую влиять на соседние контексты.
Например, z-index: 999999 у вложенного элемента не гарантирует, что он окажется выше элемента с меньшим значением z-index, если родительский stacking context находится ниже в порядке отрисовки:
.card {
position: relative;
z-index: 1;
}
.modal {
position: absolute;
z-index: 999999;
}
.header {
position: relative;
z-index: 10;
}
Если .modal находится внутри .card, браузер сначала сравнивает .card и .header в родительском stacking context, а уже затем учитывает внутренние слои .card. Высокий z-index дочернего элемента не может изменить положение родительского контекста.
Stacking context создаётся не только через position и z-index. Многие CSS-свойства меняют модель композиции слоёв и создают отдельный контекст наложения:
.component {
opacity: 0.99;
transform: translateZ(0);
filter: blur(5px);
isolation: isolate;
contain: paint;
}
В реальных проектах чаще всего проблемы возникают у модальных окон, dropdown, popover и tooltip-компонентов, когда один из родителей создаёт собственный stacking context:
.layout {
transform: translate3d(0, 0, 0);
}
.dropdown {
position: absolute;
z-index: 999999;
}
В такой ситуации увеличение z-index не помогает, потому что элемент остаётся внутри ограниченного контекста .layout.
Отдельный случай — position: fixed. Обычно такой элемент привязан к viewport, но некоторые свойства родителей изменяют его containing block:
.page {
transform: translateZ(0);
}
.modal {
position: fixed;
inset: 0;
z-index: 10000;
}
Теперь modal рассчитывает позицию относительно .page, а не viewport. Поэтому проблема решается не изменением z-index, а изменением структуры DOM.
Для глобальных интерфейсных слоёв используют отдельный DOM-слот вне основного дерева приложения. Такой подход лежит в основе portal-механизма современных UI-библиотек:
Также необходимо учитывать, что не все проблемы перекрытия связаны со stacking context. Например, overflow: hidden может обрезать дочерний элемент независимо от его z-index:
.container {
overflow: hidden;
}
.dropdown {
position: absolute;
z-index: 1000;
}
При отладке проблем со слоями необходимо проверять всю цепочку родителей: наличие stacking context, ограничения overflow, изменённый containing block и фактическое расположение элементов в DOM.
🔥 z-index — это только один параметр системы композиции браузера. В сложных интерфейсах реальный порядок отображения определяется структурой stacking context.
📣 Code Ready | #практика
z-index не является глобальной системой нумерации слоёв страницы. Браузер строит дерево stacking context, где каждый контекст отрисовывается независимо. Значение z-index сравнивается только внутри текущего контекста и не позволяет дочернему элементу напрямую влиять на соседние контексты.
Например, z-index: 999999 у вложенного элемента не гарантирует, что он окажется выше элемента с меньшим значением z-index, если родительский stacking context находится ниже в порядке отрисовки:
.card {
position: relative;
z-index: 1;
}
.modal {
position: absolute;
z-index: 999999;
}
.header {
position: relative;
z-index: 10;
}
Если .modal находится внутри .card, браузер сначала сравнивает .card и .header в родительском stacking context, а уже затем учитывает внутренние слои .card. Высокий z-index дочернего элемента не может изменить положение родительского контекста.
Stacking context создаётся не только через position и z-index. Многие CSS-свойства меняют модель композиции слоёв и создают отдельный контекст наложения:
.component {
opacity: 0.99;
transform: translateZ(0);
filter: blur(5px);
isolation: isolate;
contain: paint;
}
В реальных проектах чаще всего проблемы возникают у модальных окон, dropdown, popover и tooltip-компонентов, когда один из родителей создаёт собственный stacking context:
.layout {
transform: translate3d(0, 0, 0);
}
.dropdown {
position: absolute;
z-index: 999999;
}
В такой ситуации увеличение z-index не помогает, потому что элемент остаётся внутри ограниченного контекста .layout.
Отдельный случай — position: fixed. Обычно такой элемент привязан к viewport, но некоторые свойства родителей изменяют его containing block:
.page {
transform: translateZ(0);
}
.modal {
position: fixed;
inset: 0;
z-index: 10000;
}
Теперь modal рассчитывает позицию относительно .page, а не viewport. Поэтому проблема решается не изменением z-index, а изменением структуры DOM.
Для глобальных интерфейсных слоёв используют отдельный DOM-слот вне основного дерева приложения. Такой подход лежит в основе portal-механизма современных UI-библиотек:
Также необходимо учитывать, что не все проблемы перекрытия связаны со stacking context. Например, overflow: hidden может обрезать дочерний элемент независимо от его z-index:
.container {
overflow: hidden;
}
.dropdown {
position: absolute;
z-index: 1000;
}
При отладке проблем со слоями необходимо проверять всю цепочку родителей: наличие stacking context, ограничения overflow, изменённый containing block и фактическое расположение элементов в DOM.
🔥 z-index — это только один параметр системы композиции браузера. В сложных интерфейсах реальный порядок отображения определяется структурой stacking context.
📣 Code Ready | #практика