Ответ вслух Middle Позиционирование и z-index обновлено

Выпадающее меню прячется под блоком

Вопрос

Выпадающее меню прячется под соседним блоком, хотя у него z-index: 1000. Как будешь разбираться?

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

Сначала проверяю, что меню вообще позиционировано, иначе его z-index игнорируется. Дальше иду вверх по предкам и ищу, кто создаёт контекст наложения: позиционированный элемент с z-index, transform, opacity меньше единицы, filter.

Что должно прозвучать в ответе

  • Проверить, что у меню есть `position` (или оно flex/grid-элемент), иначе `z-index` не работает

  • Найти ближайшего предка, создающего контекст наложения (`z-index`, `transform`, `opacity`, `filter`)

  • Сравнивать уровни нужно у предков в общем контексте, а не у меню и соседа

  • Проверить `overflow: hidden` у предков: меню может быть обрезано, а не перекрыто

  • Решение: поднять контекст предка, убрать лишний контекст или вынести меню в портал

  • Завести шкалу уровней (токены) вместо гонки чисел

Что могут спросить следом

  • Как найти, кто создал контекст наложения, в DevTools?
  • Чем поможет isolation: isolate?
  • Как top layer у <dialog> и popover решает эту проблему?

Разбор

Сначала проверяю, что меню вообще позиционировано, иначе его z-index игнорируется. Дальше иду вверх по предкам и ищу, кто создаёт контекст наложения: позиционированный элемент с z-index, transform, opacity меньше единицы, filter. Если такой предок есть, меню заперто внутри него, и его 1000 сравнивается только с соседями внутри. Снаружи сравниваются уже уровни предков в общем контексте, и если предок ниже соседнего блока, меню проиграет при любом числе. Ещё отдельно проверяю overflow: hidden у обёрток: тогда меню не перекрыто, а обрезано, и z-index вообще ни при чём. Решения: поднять уровень нужного предка, убрать случайный контекст вроде ненужного transform, или отрендерить меню в портал в конце body. Для нативных попапов есть <dialog> и атрибут popover, они попадают в top layer поверх всего. И в проекте завожу шкалу уровней в переменных, чтобы не было гонки девяток.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.