Нюансы stacking-context
Проблема: при смене новой группы хедера в теме Dawn (Shopify) даже идентичной, мобильное меню начинало показываться под hero блоком.
Это действительно выглядит как мистика, но у этого есть логичное объяснение.
Анализ проблемы
Смотрим на CSS в base.css:
/* section-header */
.section-header.shopify-section-group-header-group {
z-index: 3;
}
.shopify-section-group-header-group {
z-index: 4;
}
.section-header ~ .shopify-section-group-header-group {
z-index: initial;
}
Что происходит
1. Когда используете {% sections 'header-group' %}:
- Shopify генерирует CSS-класс
.shopify-section-group-header-group - Этот класс получает
z-index: 4из CSS выше - Меню работает правильно
2. Когда меняете на {% sections 'custom-header-group' %}:
- Shopify генерирует CSS-класс
.shopify-section-group-custom-header-group - В CSS НЕТ стилей для этого класса!
- z-index остается по умолчанию (auto/0)
- Меню “проваливается” под hero
Решение
Добавьте CSS для вашей кастомной группы:
/* Добавьте в ваш кастомный CSS файл или в base.css */
.shopify-section-group-custom-header-group {
z-index: 4;
}
.section-header.shopify-section-group-custom-header-group {
z-index: 3;
}
Почему Shopify так делает
- Shopify автоматически генерирует CSS-классы на основе имени группы секций
- В базовых стилях прописаны только стандартные имена (
header-group,footer-group) - Кастомные имена требуют дополнительных CSS-правил
Вывод
Проблема не в JSON-файле (он действительно идентичный), а в отсутствии CSS-стилей для кастомного имени группы секций. Добавьте CSS выше — и всё заработает!
Давайте разберем механику stacking contexts (контексты наложения) в CSS и почему именно z-index: 4 на родительском элементе решил проблему.
Анализ DOM структуры
Смотря на theme.liquid, видим:
<body>
{% sections 'custom-header-group' %}
<!-- header здесь -->
<main>
{{ content_for_layout }}
<!-- hero здесь -->
</main>
</body>
Что происходило БЕЗ CSS правил
1. Shopify генерирует контейнер для группы секций:
<div class="shopify-section-group-custom-header-group">
<header class="header">
<div id="menu-drawer">...</div>
</header>
</div>
2. По умолчанию у этого контейнера:
position: static(обычный поток)z-index: auto(нет собственного stacking context)
3. В то же время у hero-блока:
.banner__box {
position: relative;
z-index: 1;
}
Ключевой момент: Порядок в DOM + Stacking Context
Правило CSS: Если элементы находятся в разных stacking context или в обычном потоке, то элемент, который идёт позже в DOM, отображается поверх предыдущего.
В нашем случае:
- Header группа идёт первой в DOM
- Main с hero идёт после header группы
- У
.banner__boxестьposition: relative+z-index: 1→ создаёт stacking context - У header группы нет своего stacking context → она остаётся в обычном потоке
Результат: Hero отображается поверх header’а, даже если у menu-drawer поставить z-index: 999999, потому что menu-drawer “заперт” внутри обычного потока, а hero создал свой stacking context поверх.
Что происходит С CSS правилами
.shopify-section-group-custom-header-group {
z-index: 4; /* Создаёт stacking context для всей группы */
}
Теперь:
- Header группа получает
z-index: 4→ создаёт свой stacking context - Hero имеет
z-index: 1в своём stacking context - 4 > 1 → Header группа отображается поверх hero
Почему z-index: -1 для hero работал
.banner {
z-index: -1;
}
Это “утапливало” hero ниже обычного потока (ниже z-index: 0), поэтому header снова становился видимым. Но это “костыль”, а не правильное решение.
Визуализация Stacking Contexts
БЕЗ CSS правил:
Document (z-index: auto)
├── Header группа (z-index: auto) ← обычный поток
│ └── menu-drawer (z-index: любой) ← "заперт" в обычном потоке
└── Main (z-index: auto)
└── Hero (position: relative, z-index: 1) ← создаёт stacking context, идёт после в DOM
С CSS правилами:
Document (z-index: auto)
├── Header группа (z-index: 4) ← создаёт stacking context
│ └── menu-drawer (z-index: любой)
└── Main (z-index: auto)
└── Hero (z-index: 1) ← в своём stacking context
Вывод
Проблема была не в том, что header “уходил под hero по z-index”, а в том, что:
- Header группа не имела своего stacking context и оставалась в обычном потоке
- Hero создавал stacking context и шёл после в DOM
- DOM порядок + отсутствие stacking context у header’а = hero поверх
Добавление z-index: 4 к header группе создало равноправный stacking context, где уже работают правила сравнения z-index между header’ом и hero.
Это классическая проблема CSS: элементы в разных stacking context не сравнивают свои z-index напрямую — важен z-index их родительских контекстов!