Чи стикалися ви колись із тим, що задаєте елементу
z-index: 9999, а він усе ніяк не хоче вигулькувати поверх іншого елементу? Якщо так, то вітаю — ви побачили, як на практиці працює stacking context.Це така собі "область видимості", в межах якої застосовуються правила накладання елементів. Ми зазвичай це бачимо як "один елемент закриває інший", бо екран не передає нам глибину. Але насправді ця глибина існує, просто вона віртуальна.
Давайте розглянемо ось таку структуру для прикладу:
<div>1</div>
<div id="stack-1">
<div>2</div>
<div>3</div>
<div>4</div>
<div id="stack-1-1">
<div>5</div>
<div>6</div>
</div>
</div>
<div id="stack-2">
<div>7</div>
<div>8</div>
<div id="stack-2-1">
<div>9</div>
<div>10</div>
</div>
</div>
А тепер уявіть собі стос папірців. Цей стос буде представляти відображення усіх елементів з числами всередині (але не самі елементи, це важливо). Отой stacking order визначатиме порядок цих папірців у стосі. За замовчуванням він відповідатиме порядку й вкладеності цих елементів в DOM. Проте, якщо, до прикладу, листку з номером 8 призначити
z-index: 1, він одразу переміститься наперед.Чому? Для цього треба зрозуміти, як саме визначається порядок всередині контексту. Так от, шари контексту впорядковуються наступним чином:
1. Фон і бордер елемента, що створює контекст;
2. Елементи з негативним z-index;
3. Блоки без позиціонування (static);
4. Елементи з z-index: auto;
5. Елементи з додатним z-index (у порядку значень).
А тепер нехай ми задамо елементу
#stack-2 position: relative. Ми побачимо, що восьмий папірець уже не опиняється з самого верху стосу. Чому? Бо ми перетворили #stack-2 на прозорий файлик, і тепер папірці в ньому можуть змінювати свій порядок лише всередині нього. Ми створили новий stacking context.Насправді, створити його набагато легше, ніж нам здається. Окрім усім відомого
position зі значенням, відмінним від static (і то з умовами), до утворення нового контексту може призвести використання різноманітних стилів, про деякі з них ви й не могли подумати, що вони здатні на подібне.Наприклад, елементи, що мають
z-index (не auto) та знаходяться всередині flex чи ґріду. Або з mask. Чи з container-type з певними значеннями (не всіма!). Найпідступніше, напевно, це opacity зі значенням менше 1. А повний перелік умов можна буде знайти за прикріпленим посиланням нижче.На сторінці завжди існує щонайменше один такий контекст, утворений кореневим елементом. І, що очевидно, ці контексти можуть вкладатися один в один, як ті самі прозорі файлики з папірцями. Це завжди варто мати на увазі, бо навіть найбільший
z-index не зможе вирватися за межі свого контексту.Тому найпершою порадою буде не зловживати
position: absolute та особливо z-index, і вживати інших заходів для керування розташуванням відображення. Якщо ми говоримо про модалки та тултипи, то краще за можливості використовувати той самий dialog для модалок та властивість popover для других. Якщо показувати ці елементи за допомогою API showModal, showPopover, то вони тоді рендеряться в так званому top-layer, і відпаде потреба вручну керувати їхнім розташуванням.В двох словах — слідкуйте за stacking context та памʼятайте, що загорнути купку елементів у файлик на ділі дуже просто, але — не завжди очевидно.
Що почитати:
📖 MDN: Stacking context
📖 MDN: Understanding z-index
📖 MDN: Top layer
Що почитати душнілам:
📖 W3C: z-index
📖 CSSWG: Containment Module Level 3
Як і завжди, з мене цікавий допис, а з вас вподобайка, поширення і донат на детектори дронів для 115 бригади на Покровський напрямок.
@babichdev