8.6 KiB
8.6 KiB
ТРЗ — ET-014: Z-index конфликт terrain-popup vs sheet-gps-filters
Work Item: ET-014 Связан с BRD: 01-brd.md Тип задачи: Bug-fix (UI / стили / DOM-stacking)
1. Анализ текущего состояния
1.1 DOM-структура (как есть)
#terrain-popup(src/web/index.html:43) —position: fixed,z-index: 500(src/web/app.css:785-795). Открывается по клику на кнопку «Рельеф» (#terrain-toggleв#map-controls-r). Содержит чекбоксы слоёв, переключатели подложки и единиц, а также кнопку-ссылку#public-tracks-filters-btnс текстом «Фильтры…».#sheet-gps-filters(src/web/index.html:478) — класс.bottom-sheet,position: fixed,z-index: 400(src/web/app.css:183-196). Открывается черезtogglePublicTracksFiltersSheet()вsrc/web/gps_tracks.js:737, который вызываетopenSheet('sheet-gps-filters').#sheet-backdrop(src/web/index.html:19) —z-index: 390(src/web/app.css:222-228). На mobile перекрывает экран при открытом sheet'е; на desktop скрыт (#sheet-backdrop { display: none; }в media-query,src/web/app.css:543).
1.2 Стек z-index в проекте (для ориентира)
| Элемент | z-index | Файл/строка |
|---|---|---|
#map |
0 | app.css:68 |
#no-data-warning |
200 | app.css:410 |
#sheet-backdrop |
390 | app.css:225 |
.bottom-sheet |
400 | app.css:188 |
#map-controls-r |
400 | app.css:129 |
.terrain-popup |
500 | app.css:787 |
#marker-dialog |
500 | app.css:399 |
#search-panel |
600 | app.css:1101 |
#ruler-info |
600 | app.css:1122 |
1.3 Корень проблемы
togglePublicTracksFiltersSheet()открывает sheet (z=400), но не закрывает#terrain-popup(z=500). Popup остаётся на экране и визуально/event-but перекрывает sheet.- Клик по ссылке «Фильтры…» внутри popup не триггерит
closeTerrainOnOutside(popup.contains(target) === true), поэтому popup не закрывается сам. - Backdrop sheet'а (z=390) тоже ниже popup'а (z=500), поэтому даже на mobile нет визуальной индикации, что popup стал «фоном».
2. Требования к решению
2.1 Функциональные (REQ-F)
| ID | Требование |
|---|---|
| REQ-F-01 | При открытии #sheet-gps-filters из «Фильтры…» панель #terrain-popup НЕ должна перекрывать sheet ни визуально, ни для событий ввода. |
| REQ-F-02 | Когда #sheet-gps-filters открыт, состояние кнопки #terrain-toggle (класс .active) должно быть консистентно с состоянием popup: если popup скрывается / закрывается на время открытия фильтров — кнопка не должна оставаться визуально «прижатой». |
| REQ-F-03 | После закрытия #sheet-gps-filters (через ✕, свайп вниз, клик по backdrop на mobile, либо closeAllSheets()) пользователь возвращается к карте. Возврат панели слоёв — на усмотрение архитектора (см. §3 «Варианты решения»). В любом случае не должно оставаться «фантомных» оверлеев / неактивных DOM в видимой области. |
| REQ-F-04 | Решение должно работать единообразно при инициации фильтров повторно (открыли → закрыли → открыли снова). |
| REQ-F-05 | Поведение #terrain-popup для всех других сценариев (открыть/закрыть кнопкой, кликнуть вне popup'а, переключить чекбокс/подложку/единицы) не должно регрессировать. |
| REQ-F-06 | Поведение остальных bottom-sheets (#sheet-route, #sheet-recon, #sheet-scenic, #sheet-link, #sheet-gpx) не должно регрессировать. |
| REQ-F-07 | Решение должно одинаково корректно работать в светлой и тёмной теме. |
2.2 Нефункциональные (REQ-NF)
| ID | Требование |
|---|---|
| REQ-NF-01 | Изменения локализованы во фронте (src/web/). Backend (src/api/) не затрагивается. |
| REQ-NF-02 | Нет регрессий по производительности (никаких новых тяжёлых обработчиков resize/scroll). |
| REQ-NF-03 | Если решение меняет z-index — оно не должно ломать стекинг #marker-dialog (z=500), #search-panel (z=600), #ruler-info (z=600). |
| REQ-NF-04 | Решение совместимо с PWA-режимом (PH-9, в работе): в standalone display и при наличии safe-area-inset. |
| REQ-NF-05 | Решение работает на mobile viewport 360–414 px (Chrome Android), desktop ≥1024 px (Chrome desktop). |
3. Варианты решения (на усмотрение архитектора)
Аналитик не выбирает архитектуру. Перечисляю опции, которые могут быть рассмотрены реализатором/архитектором:
- Вариант A — закрывать
#terrain-popupпри открытии sheet-gps-filters. ВtogglePublicTracksFiltersSheet()передopenSheet(...)явно скрыть popup (как делаетcloseTerrainOnOutside) и снять.activeс#terrain-toggle. Backdrop sheet'а корректно затемнит фон на mobile. - Вариант B — поднять z-index sheet'ов выше terrain-popup. Например,
.bottom-sheet { z-index: 510; }и#sheet-backdrop { z-index: 505; }. Тогда sheet физически окажется поверх popup'а. Требует проверки на не- конфликт с marker-dialog (z=500) и не-перекрытие toolbar / search-panel. - Вариант C — точечно поднять z-index только
#sheet-gps-filtersи его backdrop. Узкий хак:#sheet-gps-filters { z-index: 510; }. Менее системно, но минимальные риски регрессии для других sheet'ов.
Решение фиксируется архитектором в ADR работы (06-adr/).
4. Acceptance hooks
См. полные критерии в 03-acceptance-criteria.md.
Краткая выжимка:
- Открытие фильтров → панель полностью видна, кликабельна (mobile и desktop).
- Панель слоёв не перекрывает фильтры (визуально и для событий).
- Закрытие фильтров → возврат к карте без артефактов.
- Остальные оверлеи (marker-dialog, search-panel, ruler-info, остальные sheets) — без регрессий.
5. Тесты
См. 04-test-plan.yaml (функциональные тесты) и
04b-ui-test-cases.md (Playwright UI тест-кейсы).
6. Артефакты для модификации (ожидание аналитика)
src/web/app.css— стили stacking-context (если выбран вариант B/C).src/web/gps_tracks.js— логикаtogglePublicTracksFiltersSheet()(если выбран вариант A).- Возможно
src/web/app.js— если вopenSheet/closeAllSheetsтребуется хук «при открытии sheet закрыть popup» как универсальное решение для будущих кейсов.
Это рекомендация, конкретный набор файлов определит архитектор.