diff --git a/frontend/index.html b/frontend/index.html index 874a03a..3748545 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -4,7 +4,7 @@ Forbidden Stars — учёт партий diff --git a/frontend/src/styles/global.css b/frontend/src/styles/global.css index 432081c..e5cd70b 100644 --- a/frontend/src/styles/global.css +++ b/frontend/src/styles/global.css @@ -11,6 +11,11 @@ html, body, #root { margin: 0; } +/* Высота каркаса — по видимой области (dvh): на мобильных 100% берётся от layout + viewport, который меняется при сворачивании адресной строки. Правило выше остаётся + фоллбэком для движков без dvh. */ +#root { height: 100dvh; } + body { background: var(--bg); color: var(--text); @@ -18,6 +23,7 @@ body { Arial, sans-serif; -webkit-font-smoothing: antialiased; overscroll-behavior-y: none; + overflow: hidden; /* прокручивается только .app-main */ } a { color: var(--accent-2); text-decoration: none; } @@ -190,7 +196,7 @@ input:focus, select:focus, textarea:focus { border-color: var(--accent); } .toast { position: fixed; left: 50%; - bottom: calc(var(--bottombar-height) + 80px); + bottom: calc(var(--bottombar-height) + 16px); transform: translateX(-50%); background: var(--surface-2); border: 1px solid var(--border); @@ -206,7 +212,7 @@ input:focus, select:focus, textarea:focus { border-color: var(--accent); } /* ─── Уведомления ─────────────────────────────────────────────────────────── */ /* Зоны верхней панели: слева back/заголовок, по центру название, справа колокольчик */ -.top-bar-left { display: flex; align-items: center; min-width: 0; } +.top-bar-left { display: flex; align-items: center; min-width: 0; flex: 0 1 auto; } .top-bar-center { flex: 1; text-align: center; @@ -215,7 +221,7 @@ input:focus, select:focus, textarea:focus { border-color: var(--accent); } white-space: nowrap; padding: 0 8px; } -.top-bar-right { display: flex; align-items: center; } +.top-bar-right { display: flex; align-items: center; flex: none; } .top-bar-home { background: none; border: none; @@ -223,6 +229,11 @@ input:focus, select:focus, textarea:focus { border-color: var(--accent); } color: var(--text); font-weight: 700; font-size: 17px; + /* На узких экранах длинное название иначе распирает шапку по горизонтали. */ + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .notif-bell-wrap { position: relative; } @@ -258,7 +269,7 @@ input:focus, select:focus, textarea:focus { border-color: var(--accent); } top: calc(100% + 8px); right: 0; width: min(320px, 86vw); - max-height: 70vh; + max-height: 70dvh; overflow-y: auto; background: var(--surface); border: 1px solid var(--border); @@ -437,7 +448,7 @@ input:focus, select:focus, textarea:focus { border-color: var(--accent); } /* Всплывашки сверху экрана в момент прихода */ .toast-top-wrap { position: fixed; - top: calc(var(--safe-top) + 10px); + top: 10px; left: 50%; transform: translateX(-50%); width: min(var(--app-max-w), 94vw); diff --git a/frontend/src/styles/layout.css b/frontend/src/styles/layout.css index f0597ae..6854a04 100644 --- a/frontend/src/styles/layout.css +++ b/frontend/src/styles/layout.css @@ -2,42 +2,44 @@ position: relative; max-width: var(--app-max-w); margin: 0 auto; - min-height: 100%; + height: 100%; display: flex; flex-direction: column; background: var(--bg); box-shadow: 0 0 40px rgba(0, 0, 0, 0.5); } +/* Шапка вне прокручиваемой области по построению — sticky ей больше не нужен. */ .top-bar { - position: sticky; - top: 0; - z-index: 10; + flex: none; display: flex; align-items: center; justify-content: space-between; - padding: calc(var(--safe-top) + 12px) 16px 12px; + padding: 12px 16px; background: var(--surface); border-bottom: 1px solid var(--border); } .top-bar .title { font-weight: 700; font-size: 17px; } +/* Единственная прокручиваемая область приложения. */ .app-main { flex: 1; + min-height: 0; /* без этого flex-элемент не сжимается и прокрутка уходит в body */ overflow-y: auto; + overscroll-behavior: contain; + -webkit-overflow-scrolling: touch; padding: 14px; - padding-bottom: calc(var(--bottombar-height) + var(--fab-height) + var(--safe-bottom) + 28px); + /* Подвал теперь в потоке — компенсировать нужно только выступающий купол FAB. */ + padding-bottom: 24px; } +/* Панель — обычный элемент флекс-колонки, не fixed: в мобильных браузерах со + скрывающейся адресной строкой fixed-подвал дёргается при прокрутке. + position: relative обязателен — на нём держится absolute-позиционирование .fab. */ .bottom-bar { - position: fixed; - bottom: 0; - left: 50%; - transform: translateX(-50%); - width: 100%; - max-width: var(--app-max-w); - height: calc(var(--bottombar-height) + var(--safe-bottom)); - padding-bottom: var(--safe-bottom); + position: relative; + flex: none; + height: var(--bottombar-height); background: var(--surface); border-top: 1px solid var(--border); display: flex; @@ -61,13 +63,14 @@ .bottom-bar .slot .name { color: var(--text); font-weight: 600; max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .bottom-bar .spacer { width: var(--fab-width); flex: 0 0 var(--fab-width); } -/* Круг создания партии: полукруг-купол, по центру разделяет слоты, смещён вниз - (база у нижней кромки панели) и поднят на передний план (z-index выше панели). */ +/* Круг создания партии: полукруг-купол, по центру разделяет слоты, базой стоит на + нижнем крае экрана и поднят на передний план (z-index выше панели). Ширина вдвое + больше высоты (140x70) — над кромкой панели купол выступает на 6px. */ .fab { position: absolute; left: 50%; transform: translateX(-50%); - bottom: calc(var(--safe-bottom) + 8px); + bottom: 0; width: var(--fab-width); height: var(--fab-height); border: 1px solid var(--accent); @@ -131,6 +134,7 @@ /* Вкладки админки: горизонтальная карусель (не ломают вёрстку при переполнении) */ .admin-tabs { + flex: none; display: flex; gap: 8px; padding: 10px 14px; @@ -218,7 +222,7 @@ position: fixed; top: 0; right: 0; - height: 100%; + height: 100dvh; width: min(300px, 84vw); background: var(--surface); border-left: 1px solid var(--border); @@ -228,7 +232,6 @@ z-index: 61; display: flex; flex-direction: column; - padding-top: var(--safe-top); } .side-menu.open { transform: translateX(0); } diff --git a/frontend/src/styles/tokens.css b/frontend/src/styles/tokens.css index 44a25ae..71d0bdc 100644 --- a/frontend/src/styles/tokens.css +++ b/frontend/src/styles/tokens.css @@ -16,12 +16,10 @@ /* Размеры */ --app-max-w: 480px; --bottombar-height: 64px; - --fab-width: 125px; - --fab-height: 62.5px; + --fab-width: 140px; + --fab-height: 70px; --radius: 14px; --radius-sm: 10px; - --safe-bottom: env(safe-area-inset-bottom, 0px); - --safe-top: env(safe-area-inset-top, 0px); /* Брейкпоинты (для справки) */ --bp-lg: 768px;