Вопрос был: «нужно полностью перейти к относительному позиционированию — это ведь исправит проблему?»
Нет. Ни одно из найденных наложений не вызвано position:absolute.
Все три — переполнение обычного потока (шапка шире колонки) и один плавающий элемент,
под который не зарезервировано место. Сплошная замена на relative их не тронет,
зато сломает модалки, выпадающие меню, бейджи на фото и липкую шапку.
Правки внесены точечно, четырьмя файлами, и перепроверены тем же инструментом: на 144 замерах (10 маршрутов × 14 ширин окна) не осталось ни переполнения шапки, ни наездов на неё, ни горизонтальной прокрутки. Что именно изменилось — в разделе «После правок».
Ширина в CSS-пикселях. Масштаб Windows 125 % превращает ноутбук 1366 px в окно 1093 px, а монитор 1920 px — в 1536 px; при 150 % это 911 и 1280 px. Именно поэтому жалоба звучит как «зависит от разрешения экрана».
Границы измерены Playwright/Chromium на бою (гость) и с подменой API для закрытых страниц (логин «carletoajdavisrnc253» в шапке). Верхняя граница чата и шапки зависит от длины логина: цифры даны для этого логина, для гостя с надписью «Профиль» они на 95 px ниже.
Страница чата — это flex-ряд: слева история диалогов w-64 (256 px), справа панель «Из базы» шириной 384 px, и TopBar смонтирован внутри средней колонки. Панель открыта по умолчанию на любом экране от 768 px (defaultFeedOpen()), поэтому средней колонке достаётся «ширина окна минус 640 px».
Шапка же — сетка grid-cols-[1fr_auto_1fr], у которой средняя дорожка (шесть пунктов меню с подписями) имеет минимальную ширину контента 636 px, а вся шапка с логотипом и аккаунтом — 977 px. Сетка не умеет сжиматься ниже минимума контента, она переполняет контейнер вправо. У шапки z-30, у панели z-index нет — поэтому пункты меню рисуются поверх заголовка панели. Это и есть «блок справа залез на верхний бар».
| Окно | Колонка чата | Нужно шапке | Не хватает | Что видно |
|---|---|---|---|---|
| 800 | 160 | 977 | 817 | документ 1233 px — горизонтальная прокрутка; меню и аккаунт целиком на панели и за окном |
| 911 | 271 | 977 | 706 | «История», «Радар», «Сообщения» на заголовке панели; «Аналитика» и аккаунт за окном |
| 1024 | 384 | 977 | 593 | «Радар», «Сообщения», «Аналитика» и аккаунт поверх панели; документ 1233 px |
| 1093 | 453 | 977 | 524 | «Сообщения», «Аналитика» и аккаунт поверх панели; документ 1233 px |
| 1280 | 640 | 977 | 337 | «Сообщения», «Аналитика» и аккаунт поверх панели |
| 1366 | 726 | 977 | 251 | «Аналитика» обрезана, аватар с логином поверх заголовка «Из базы» |
| 1536 | 896 | 977 | 81 | логин заезжает на панель на 81 px |
| 1920 | 1280 | 977 | — | помещается |
Сделано
ChatPage.tsx обёрнут в flex h-[100svh] flex-col: шапка стоит первой строкой на всю ширину окна, под ней flex min-h-0 flex-1 с прежним рядом «история · чат · панель». Шапке теперь достаётся ширина окна, а не остаток. Кнопка-бургер из слота left работает как раньше, мобильная раскладка не изменилась.
Замер после правки: на всех восьми ширинах от 800 до 1920 px переполнение шапки равно нулю (было от 81 до 817 px).
Тот же механизм без чужих колонок: с 768 px в шапке появляется полное меню, но минимальная ширина её содержимого — 882 px для гостя и 977 px для этого логина. На лендинге корень overflow-x-hidden просто отрезает кнопку профиля; на /analytics, /search, /account и остальных страницах документ становится шире окна (замер: scrollWidth 882 при окне 768) и появляется горизонтальная прокрутка.
Логин в шапке не ограничен по ширине, поэтому граница плавает от пользователя к пользователю — ещё одна причина, почему проблема «то есть, то нет».
Сделано
Подписи пунктов меню переведены на hidden lg:inline: между 768 и 1023 px меню иконочное (≈ 280 px вместо 636), название пункта переехало в title, так что при наведении оно видно. Логин ограничен max-w-[8rem] truncate — длинное имя больше не раздувает шапку и обрезается многоточием.
Замер после правки: на 768 и 800 px переполнение ушло (было 114 и 82 px у гостя, 177 px под логином), горизонтальной прокрутки на закрытых страницах нет.
Единственный случай, где виноват именно плавающий элемент — и то не потому, что он fixed, а потому, что под него не зарезервировано место. Рейл прижат к правому краю окна (right-5, ширина 32 px), а контент лендинга тянется до max-w-6xl (1152 px) с отступом 24 px. Пока окно уже 1208 px, правый край карточек заходит под овалы рейла; при наведении к ним ещё и выезжает подпись шириной до 330 px.
Сделано
Рейл показывается с xl: (1280 px), лента чипов SectionChips живёт до xl:hidden. Замер после правки: на 768–1207 px рейла нет, вместо него чипы; на 1280 px левый край рейла — 1228 px, правый край карточек — 1192 px, то есть между ними 36 px зазора.
После исправления пункта 1 шапка с панелью не конфликтует, но при 1024 px чату оставалось бы 384 px — ширина телефона. Порог автораскрытия поднят до 1280 px: колонка панели по-прежнему существует с 768 px, просто закрытой, и открывается язычком.
Осталось на ваше решение. Открыть панель язычком можно и на 800 px — тогда чату достаётся 160 px, и читать его нельзя. Это поведение было и раньше; чтобы убрать и его, панель на 768–1279 px должна открываться поверх страницы (как на телефоне), а не раздвигать колонки. Это уже правка самой панели, я её не делал.
Изменены четыре файла. Прогон повторён на сборке с правками: те же маршруты, те же ширины окна, тот же инструмент. Проверка типов проходит.
| Файл | Что изменено |
|---|---|
| pages/ChatPage.tsx | Шапка вынесена из средней колонки в отдельную строку над всеми тремя колонками. |
| components/layout/TopBar.tsx | Подписи пунктов меню с lg: вместо sm:, название пункта в title, логин ограничен 8rem с многоточием. |
| components/landing/SectionRail.tsx components/landing/SectionChips.tsx | Рейл разделов показывается с 1280 px, лента чипов — до 1280 px. |
| store/chatStore.ts | Панель «Из базы» раскрывается сама с 1280 px вместо 768 px. |
| Маршрут | Окно | Было | Стало |
|---|---|---|---|
| /chat | 800 | 817 | 0 |
| /chat | 911 | 706 | 0 |
| /chat | 1024 | 593 | 0 |
| /chat | 1093 | 524 | 0 |
| /chat | 1280 | 337 | 0 |
| /chat | 1366 | 251 | 0 |
| /account | 800 | 177 | 0 |
| /analytics | 800 | 177 | 0 |
| /history | 800 | 177 | 0 |
| /messages | 800 | 177 | 0 |
| /radar | 800 | 177 | 0 |
| /search | 800 | 177 | 0 |
| /search/results | 800 | 177 | 0 |
| / (гость) | 768 | 114 | 0 |
| /analytics (гость) | 768 | 114 | 0 |
| / (гость) | 800 | 82 | 0 |
| /analytics (гость) | 800 | 82 | 0 |
| /chat | 1536 | 81 | 0 |
| /account | 911 | 66 | 0 |
| /analytics | 911 | 66 | 0 |
| /history | 911 | 66 | 0 |
| /messages | 911 | 66 | 0 |
| /radar | 911 | 66 | 0 |
| /search | 911 | 66 | 0 |
| /search/results | 911 | 66 | 0 |
Переполнение шапки в пикселях: ширина её содержимого минус ширина коробки, в которую она поставлена. Ноль означает, что содержимое помещается. Строки, где до правок переполнения не было, опущены.
Просмотрены все 119 употреблений в frontend-agent/src и frontend-admin/src (то, что nginx на бою отдаёт с / и /admin/; frontend/ и frontend-v2/ на бой не попадают). У каждого absolute проверен ближайший позиционированный предок — он есть везде. Ниже группы по роли; «оставить» означает, что в обычном потоке эту вещь выразить нельзя.
| Роль | Штук | Примеры | Вердикт |
|---|---|---|---|
Модалки и оверлеи: fixed inset-0 + карточка по центру, кнопки закрытия | 29 | CarModal:1135, CarModalHost:62/75, OrderModal:124, Sheet:147, CrossCountry*Modal, ComparePicker:110, AccountPage:667/889, CarrierTurnkeyBlock:53, dialog.tsx:18/39/45, кнопки закрытия AccountPage:675/897, OrderModal:135, Sheet:224, toast:71, CarModal:1170/1175, ApiDocsPage:1248/1338, admin ItemDrawer:45, admin ui:119 | оставить |
Бейджи, кнопки и подложки на фото внутри relative-карточки | 37 | AgentCarCard:208–260, LandingCarCard:67–135, Gallery:124–150, AccountPage:251–428, UserPage:351, SimilarCard:28, ComparePicker:92, CarGrid:103, AlertCard:124, AnalyticsPage:300–304, CarRibbon:221, ListingMetricsPanel:333, bits:103, CompareTable:101 | оставить |
| Выпадающие меню и подсказки под полем/кнопкой | 10 | TopBar:173, AgentCarCard:347/352, SuggestInput:214, searchable-select:272, PlatformSelector:183, HomePage:315, SectionRail:67, admin Bell:45/46 | оставить |
| Иконка внутри поля ввода, галочка в select | 6 | SuggestInput:197, ConversationSidebar:40/55, UserPage:277, select:110, searchable-select:327, CrossCountryPickerModal:303 | оставить |
| Липкие панели: шапка, лента чипов, композер чата, шапки таблиц | 17 | TopBar:109, SectionChips:49, ChatPage:165, CompareTable:123, SearchFilters:446, ApiDocsPage:395/562, CarrierLayout:79, admin Layout:78, admin thead ×7, admin ui:127 | оставить |
| Плавающие элементы у края окна | 7 | SectionRail:54 · InventoryDrawer:144/168 · BottomTabBar:85 · toast.tsx:17 · CarrierLayout:106/113 · admin Layout:92/99 | SectionRail — исправить, остальные оставить |
| Всплывающие подсказки аналитики порталом в body по координатам курсора | 2 | bits.tsx:164, :223 (left зажат в 96…100vw−96) | оставить |
| Декор: свечение, шиммер, фон-«сияние», кольцо у язычка, зона касания 44 px, бейджи непрочитанного | 10 | Composer:50/108, LandingView:286, index.css:60 (body::before), :205, :244 (.tap-44), :325 (.feed-glow), TopBar:140, BottomTabBar:117, admin Bell:38 | оставить |
Блокировка прокрутки фона под модалкой (body{position:fixed}) | 1 | lib/useBodyScrollLock.ts:25 | оставить |
Не CSS: item_type: 'fixed', «sticky»-перевозчик в сторах | 51 | CarrierConfigurationDetailPage, api/carrier.ts, carrierOffersStore, marketCountry | ложные срабатывания grep |
Отдельно проверено: в TopBar комментарий про backdrop-filter верен — он делает шапку containing block для fixed-потомков, поэтому оверлей меню аккаунта закрывается по клику снаружи через слушатель на document, а не через fixed inset-0. То же учтено в Sheet и CarrierTurnkeyBlock. Это правильные решения, менять их не нужно.
Для каждой пары «страница × окно»: ширина содержимого шапки против доступной ей ширины. Красным — переполнение (то, что видно как обрезанную кнопку, прокрутку или наезд). Закрытые страницы сняты с подменой API: данные пустые, геометрия оболочки честная.
| Окно | / (гость) | /analytics (гость) | /chat | /search | /search/results | /radar | /history | /account | /messages | /analytics |
|---|---|---|---|---|---|---|---|---|---|---|
| 768 | 882/768 | 882/768 | — | — | — | — | — | — | — | — |
| 800 | 882/800 | 882/800 | 977/160 | 977/800 | 977/800 | 977/800 | 977/800 | 977/800 | 977/800 | 977/800 |
| 853 | 882/853 | 882/853 | — | — | — | — | — | — | — | — |
| 911 | ✓ | ✓ | 977/271 | 977/911 | 977/911 | 977/911 | 977/911 | 977/911 | 977/911 | 977/911 |
| 960 | ✓ | ✓ | — | — | — | — | — | — | — | — |
| 1000 | ✓ | ✓ | — | — | — | — | — | — | — | — |
| 1024 | рейл | ✓ | 977/384 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| 1093 | рейл | ✓ | 977/453 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| 1152 | рейл | ✓ | — | — | — | — | — | — | — | — |
| 1280 | ✓ | ✓ | 977/640 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| 1366 | ✓ | ✓ | 977/726 | ✓ | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| 1440 | ✓ | ✓ | — | — | — | — | — | — | — | — |
| 1536 | ✓ | ✓ | 977/896 | — | ✓ | ✓ | — | ✓ | ✓ | ✓ |
| 1920 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
photo_2026-09-08_18-08-40.jpg с вашего ПК получить не удалось: обратный туннель ведёт на Linux-машину joda, а файл лежит на Windows. Диагноз собран по собственным снимкам боя; если на вашем скриншоте другая страница — положите файл в ~/Downloads на joda, и я сверю./docs/api живёт на инлайновых стилях со своей шапкой; наложений на десктопе нет, её мобильная переделка — отдельная волна В6./admin/) просмотрена только по коду: 20 употреблений, все типовые.full-update и не закоммичены. Проверены на локальной сборке с боевым API; на бою пока прежний код.scripts/mobile_audit.py стоит добавить десктопные ширины 800, 1024, 1093, 1366 и проверку «содержимое шапки не шире её коробки» — тогда такая регрессия будет валить прогон, а не приходить от пользователей. Не сделано.