HTML/CSSMiddleTechnical
Что такое CSS z-index и как работает контекст наложения (stacking context)?
z-index работает только внутри stacking context. Новый контекст создаётся при position+z-index, opacity<1, transform, filter и др. Элемент с z-index:9999 внутри контекста с низким z-index будет перекрыт.
z-index и контекст наложения (stacking context)
z-index определяет порядок отрисовки элементов вдоль оси Z (от экрана к зрителю). Но работает он не глобально — только внутри контекста наложения (stacking context), к которому принадлежит элемент.
Базовый порядок наложения без z-index
Без явного z-index элементы отрисовываются в следующем порядке (снизу вверх):
- Фоны и границы корневого элемента
- Блочные дочерние элементы (block)
- Floating-элементы
- Строчные дочерние элементы (inline)
- Positioned-элементы (
position: relative/absolute/fixed/sticky) безz-index
Как работает z-index
.box-a {
position: relative;
z-index: 1; /* выше box-b */
}
.box-b {
position: relative;
z-index: 0;
}
z-index работает только на positioned элементах (position не static) или flex/grid children.
Что создаёт новый stacking context
position: relative/absolute/fixed/sticky+z-indexнеautoopacity < 1transform,filter,clip-path,mask(любое значение кроме none)will-change: transform(или любое animatable свойство)isolation: isolate- Flex/grid item с
z-indexнеauto
Классический баг: z-index не работает
<!-- Проблема: modal перекрыт sidebar -->
<div class="sidebar" style="position: relative; z-index: 1; transform: translateZ(0);">
<!-- transform создаёт новый stacking context! -->
<div class="modal" style="position: fixed; z-index: 9999;"></div>
<!-- modal с z-index:9999 ограничен контекстом sidebar с z-index:1 -->
</div>
<div class="header" style="position: relative; z-index: 2;"></div>
<!-- header с z-index:2 перекрывает весь sidebar вместе с modal -->
Решение: вынос portal за пределы контекста
<!-- В React: portal в document.body -->
{ReactDOM.createPortal(
<div className="modal">...</div>,
document.body
)}
<!-- В Vue: Teleport -->
<Teleport to="body">
<div class="modal">...</div>
</Teleport>
<!-- В ванильном JS -->
document.body.appendChild(modalElement);
Инструмент: isolation: isolate
.card {
isolation: isolate; /* создаёт stacking context без z-index/opacity/transform */
/* теперь pseudo-элементы и дочерние элементы не вступают в конфликт с внешними */
}
Дебаггинг stacking context
/* Chrome DevTools: Elements → Computed → показывает stacking context */
/* или: расширение CSS Stacking Context Inspector */
/* В коде: проверить через getComputedStyle */
const style = getComputedStyle(el);
console.log(style.transform, style.opacity, style.zIndex);
Подводные камни
transform: translateZ(0)иwill-change: transformсоздают новый stacking context — распространённый паттерн «GPU layer hack» неожиданно ограничивает z-index дочерних модалок.opacity: 0.99(иногда используется вместоvisibility) тоже создаёт stacking context.- Fixed-элементы (
position: fixed) позиционируются относительно viewport, но если родитель имеетtransform, fixed работает относительно этого родителя — баг в спецификации, не в браузере. - Гонка z-index: избегайте глобальных
z-index: 9999— используйте именованные токены (--z-modal: 300; --z-tooltip: 400) и документируйте уровни. - Flex-дочерние элементы принимают
z-indexбезposition— неожиданно отличается от поведения block-элементов. - Backdrop-filter на родителе ограничивает fixed-позиционирование у некоторых браузеров (Safari).
Common mistakes
- Смешивать «
z-indexи stacking context» с похожим механизмом без критерия выбора. - Игнорировать риск: неверно оценить границы применения темы «
z-indexи stacking context» и получить хрупкое решение. - Показывать только синтаксис и не объяснять поведение в runtime или сборке.
What the interviewer is testing
- Объясняет почему большой
z-indexиногда не выводит элемент наверх. - Показывает на примере, как работает:
z-indexсравнивается внутри своего stacking context; новые контексты создают positioned elements, opacity меньше 1, transform, filter, isolation и другие свойства. - Называет production-нюанс и граничный случай для темы «
z-indexи stacking context».