В основе проблем с z-index лежит модель наложения
(stacking context), реализованная в браузерах. Каждый элемент на
странице участвует в иерархии слоёв, где порядок отображения
определяется не только значением z-index, но и структурой
DOM и наличием контекстов наложения.
Контекст наложения создаётся в следующих случаях:
<html>)position (relative, absolute, fixed, sticky)
и заданным z-indexopacity < 1transform, filter,
perspectiveisolation: isolatez-indexКаждый такой контекст изолирует дочерние элементы: их
z-index сравнивается только внутри этого контекста и не
влияет на соседние.
Библиотека Tippy.js создаёт всплывающие подсказки
(tooltip) как отдельные DOM-узлы, которые по умолчанию добавляются в
document.body. Это делается через опцию:
appendTo: document.body
Таким образом, tooltip вырывается из локального контекста наложения и помещается на верхний уровень DOM, где проще контролировать отображение.
По умолчанию используется z-index: 9999, что достаточно
для большинства сценариев. Однако в сложных интерфейсах этого может
оказаться недостаточно.
Tooltip оказывается под другими элементами интерфейса, например:
z-indexПричина — более высокий z-index у этих элементов или
нахождение tooltip в другом stacking context.
Если родительский элемент имеет:
transform: translateZ(0);
overflow: hidden;
то создаётся новый контекст наложения и область обрезки. В этом случае tooltip может:
Если явно задано:
appendTo: someElement
и этот элемент находится внутри stacking context, tooltip наследует ограничения этого контекста.
.tippy-box)z-index,
position)transform,
opacity, overflowВ Chrome DevTools можно включить:
Это помогает увидеть, какие элементы формируют контексты наложения.
Самый простой способ:
tippy(element, {
zIndex: 999999
});
или через CSS:
.tippy-box {
z-index: 999999 !important;
}
Однако это не всегда работает, если проблема связана с контекстами наложения.
Гарантирует, что tooltip не ограничен родительскими элементами:
tippy(element, {
appendTo: document.body
});
Это основной способ избежать проблем с overflow и
transform.
Если возможно, убрать:
transform: translateZ(0);
или заменить его на альтернативу. Это устраняет создание stacking context.
Если tooltip обрезается:
overflow: visible;
у родительского контейнера может решить проблему.
Если это невозможно — использовать
appendTo: document.body.
Tippy.js фактически реализует портал (перемещение элемента в другую часть DOM). Это стандартный подход для UI-библиотек:
Он позволяет избежать влияния локальных контекстов.
Создание системного уровня слоёв:
:root {
--z-tooltip: 1000;
--z-modal: 2000;
--z-overlay: 3000;
}
И использование:
tippy(element, {
zIndex: 1000
});
Это помогает избежать хаотичного роста z-index.
При работе с модальными окнами (например, кастомными или из UI-библиотек):
z-index: 10000+9999 оказывается под нейРешение:
tippy(element, {
zIndex: 11000
});
или динамическая установка в зависимости от контекста.
Flex и grid могут создавать stacking context при наличии
z-index. Это приводит к неожиданному поведению:
z-index не работает как ожидаетсяРешение — избегать задания z-index на контейнере без
необходимости.
Tooltip с position: absolute внутри контейнера с
position: fixed может вести себя нестабильно при
прокрутке.
Tippy.js решает это через Popper.js, но при кастомных настройках возможны артефакты.
Рекомендуется использовать:
tippy(element, {
strategy: 'fixed'
});
Tippy.js использует Popper.js для позиционирования. Popper учитывает:
Иногда проблема воспринимается как z-index, но на деле
tooltip просто перемещается внутрь видимой области.
Настройки:
tippy(element, {
popperOptions: {
modifiers: [
{
name: 'preventOverflow',
options: {
boundary: document.body
}
}
]
}
});
z-indexappendTo без понимания структуры DOMtransform на layout-обёрткахoverflow: hiddendocument.bodyz-indexoverflow и transformz-index работает только внутри одного stacking
contexttransform — частая причина скрытых проблемappendTo: document.body — основной инструмент
решенияz-index не гарантируют успехz-index