Модуль 1 · урок 7 з 14
Позиціонування і шари
Позиціонування — це те, чим роблять випадайки, тултіпи, липкі шапки й модалки.
Тут же живе найзагадковіший баг фронтенду: «я поставив z-index: 9999, а воно все одно
під сусіднім блоком». Розберемо, чому так, — і більше це питання не виникатиме.
П'ять значень position
| Значення | Відносно чого зсув | Місце в потоці | Де застосовують |
|---|---|---|---|
static | Зсуву немає взагалі | Займає | Стан за замовчуванням |
relative | Самого себе | Займає — місце лишається порожнім | Дрібний зсув; частіше — як «якір» для absolute |
absolute | Найближчого позиціонованого предка | Випадає | Бейджі, іконки в полі, випадайки |
fixed | Вікна браузера | Випадає | Шапка, модалка, кнопка-дія |
sticky | Найближчого предка зі скролом | Займає | Липкі заголовки таблиць і секцій |
Головне про absolute: від кого рахується
absolute шукає найближчого предка, у якого position не static,
і позиціонується відносно нього. Якщо такого предка немає — відносно всієї сторінки, і елемент
відлітає кудись у верхній лівий кут.
.field { position: relative; } /* якір */
.field__icon {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%); /* точне вертикальне центрування */
}
Тому правило звучить так: ставиш дитині absolute — постав батькові
relative. Це та сама пара, яка робить іконку в полі, бейдж на аватарі
й кнопку закриття в кутку картки.
transform, filter і will-change у предка теж роблять його
«якорем» для fixed-нащадків. Тобто модалка з position: fixed усередині
блока з transform: translateX(...) раптом позиціонується не відносно вікна,
а відносно цього блока. Виглядає як містика, поки не знаєш.
Sticky і чому він мовчки не працює
.table__head {
position: sticky;
top: 0; /* обов'язково: без зміщення sticky нічого не робить */
background: var(--surface); /* інакше вміст просвічуватиме крізь */
z-index: 1;
}
Три умови, без яких sticky просто поводиться як static:
- Задано хоча б одне зміщення:
top,bottom,leftабоright. - У жодного предка немає
overflow: hiddenчиauto— інакше «липкість» прив'язується до цього предка й ефект зникає. - Батько вищий за сам елемент — інакше липнути нема куди.
Контекст накладання: чому z-index не слухається
z-index порівнюється лише між сусідами в межах одного контексту накладання.
Якщо два елементи в різних контекстах, їхні числа взагалі не порівнюються — виграє той,
чий контекст вище.
z-index порівнюються лише всередині одного контексту.
Саме тому «підняти» тултіп у сусідньому контексті числом неможливо.Що створює новий контекст накладання
positionнеstaticразом із будь-якимz-index, крімauto.opacityменша за 1 — так, навіть0.99.transform,filter,backdrop-filter,perspective.will-changeна будь-якій із цих властивостей.isolation: isolate— єдиний, який роблять навмисно саме заради цього.- Елементи всередині
flexабоgridіз заданимz-index.
Як з цим жити на практиці
- Завести шкалу шарів у токенах:
--z-dropdown: 100,--z-modal: 400. - Значення тільки з цієї шкали, ніяких випадкових чисел.
- Модалки й тултіпи рендерити в кінець
<body>— в Angular це робить CDK Overlay. isolation: isolateна картці, щоб її внутрішні шари не лізли назовні.
z-index: 9999будь-де в коді.- Випадайка обрізається краєм картки — це
overflow: hiddenу предка. - Модалка з'явилась усередині панелі, а не поверх сторінки.
- Липка шапка перестала липнути після додавання скролу в контейнер.
У модулі 6 ти робитимеш модальні форми, а в модулі 5 — таблицю з липкою шапкою. Обидві ці штуки ламаються рівно на тому, що описано вище. Angular Material вирішує це за тебе через CDK Overlay, але коли щось піде не так, шукати причину доведеться саме тут.