frontend: Mobile-Höhe zusätzlich per visualViewport (Brave-Overlay-Leiste)

100dvh versagt bei Browsern, die ihre untere Leiste als Overlay zeichnen
(z. B. Brave): dvh meldet weiter die volle Höhe, Footer/Editor-Titelzeile
verschwinden dahinter. JS setzt nun --app-height aus window.visualViewport
.height (wirklich sichtbare Fläche), aktualisiert bei resize/orientationchange.
CSS-Kaskade bleibt Fallback: vh -> dvh -> var(--app-height).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-07-21 19:33:46 +02:00
co-authored by Claude Opus 4.8
parent e97d168ef6
commit 01c0ddd848
+24 -4
View File
@@ -27,12 +27,15 @@
repeating-linear-gradient(0deg,transparent 0 23px,var(--grid) 23px 24px), repeating-linear-gradient(0deg,transparent 0 23px,var(--grid) 23px 24px),
repeating-linear-gradient(90deg,transparent 0 23px,var(--grid) 23px 24px), repeating-linear-gradient(90deg,transparent 0 23px,var(--grid) 23px 24px),
var(--paper); var(--paper);
/* 100vh ist auf Mobilgeräten die *große* Viewport-Höhe (inkl. Fläche /* Mobile Viewport-Höhe: 100vh ist die *große* Höhe (inkl. Fläche hinter
hinter der unteren Browserleiste) — Footer/Editor-Titelzeile rutschen der unteren Browserleiste) — Footer/Editor-Titelzeile rutschen dahinter.
dahinter. 100dvh = dynamische Viewport-Höhe, folgt der sichtbaren 100dvh folgt der sichtbaren Fläche, versagt aber bei Browsern mit
Fläche. vh bleibt als Fallback für alte Browser. */ Overlay-Leiste (z. B. Brave). Deshalb setzt JS zusätzlich --app-height
aus window.visualViewport.height (die wirklich sichtbare Höhe). Reihen-
folge = Fallback-Kaskade: vh → dvh → exakte JS-Höhe. */
height:100vh; height:100vh;
height:100dvh; height:100dvh;
height:var(--app-height, 100dvh);
overflow:hidden; overflow:hidden;
display:flex;flex-direction:column; display:flex;flex-direction:column;
padding:24px 20px 12px; padding:24px 20px 12px;
@@ -1809,6 +1812,23 @@ function restoreState(){
/* ---------- Kleiner Bildschirm: nur ein Panel, schlanke Sprachwahl, Vollbild ---------- */ /* ---------- Kleiner Bildschirm: nur ein Panel, schlanke Sprachwahl, Vollbild ---------- */
const mqMobile = window.matchMedia('(max-width:640px)'); const mqMobile = window.matchMedia('(max-width:640px)');
function isMobile(){ return mqMobile.matches; } function isMobile(){ return mqMobile.matches; }
/* Exakte sichtbare Höhe (--app-height) aus window.visualViewport ableiten.
Nötig, weil manche Browser (z. B. Brave) ihre untere Leiste als Overlay
zeichnen: 100dvh meldet dann weiterhin die volle Höhe, und Footer/Editor-
Titelzeile verschwinden dahinter. visualViewport.height liefert die wirklich
sichtbare Fläche. Fällt es weg, greift die CSS-Kaskade (dvh/vh). */
function setAppHeight(){
const vv = window.visualViewport;
const h = vv ? vv.height : window.innerHeight;
document.documentElement.style.setProperty('--app-height', Math.round(h) + 'px');
}
setAppHeight();
window.addEventListener('resize', setAppHeight);
window.addEventListener('orientationchange', setAppHeight);
if(window.visualViewport){
window.visualViewport.addEventListener('resize', setAppHeight);
}
const legendBtn = document.getElementById('legendBtn'); const legendBtn = document.getElementById('legendBtn');
const agenda = document.querySelector('.agenda'); const agenda = document.querySelector('.agenda');
legendBtn.addEventListener('click', () => { legendBtn.addEventListener('click', () => {