From a6a2fabf057c3d5c1783c312d620d70d079ce97c Mon Sep 17 00:00:00 2001 From: Thomas Hackner Date: Mon, 20 Jul 2026 09:14:12 +0200 Subject: [PATCH] Modal-Scroll: Wrapper als definite-height Scroll-Container (Safari-safe) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ursache: Tailwinds min-h-screen (min-height:100vh) am Flex-Wrapper wächst in Safari nicht mit dem Panel – das Panel ragt sichtbar aus dem Bild, der Container meldet aber keinen Overflow → nichts scrollt, Speichern-Button ist unerreichbar (Chromium wächst dagegen mit, daher dort scheinbar ok). Fix: Die innere .min-h-screen-Box wird zum Scroll-Container mit DEFINITE height:100vh + overflow-y:auto (+ -webkit-overflow-scrolling:touch). Der Backdrop hält overflow:hidden. margin:auto am Panel zentriert kurze Modals und vermeidet Top-Clipping bei langen. Wirkt in Safari, Chrome, Firefox, iOS und Android (verifiziert via Chromium desktop + iPhone-Touch). Zusätzlich Cache-Busting für styles.css (?v=) am , damit ein hart zwischengespeichertes altes Stylesheet nach einem Deploy garantiert neu geladen wird. Co-Authored-By: Claude --- public/css/styles.css | 26 +++++++++++++++----------- server.js | 12 ++++++++++++ views/partials/head.ejs | 2 +- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/public/css/styles.css b/public/css/styles.css index 6b2328b..ab981f4 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -452,20 +452,24 @@ button.loading::after { ============================================ */ /* Modals: the overlay locks body scroll (overflow:hidden on ), so a panel - taller than the viewport would have its bottom cut off and the Save button - unreachable. Let the OVERLAY itself scroll like a page — the panel grows to - its natural height, and the overlay scrolls to reveal it. The panel uses - `margin:auto`, which centers a short panel but — unlike `align-items:center` - — does NOT clip the top when the panel is taller than the viewport (the - classic flexbox top-clip bug), so both the close button (top) and the Save - button (bottom) stay reachable. Applies on every screen size: the - Bewerbung-hinzufügen form has enough fields (Datum bis Interne Notizen) to - overflow even on a laptop, not just a phone. */ + taller than the viewport must scroll. The scroll container is the INNER + wrapper, not the backdrop, and it gets a DEFINITE height:100vh + overflow-y:auto. + A mere min-height:100vh (Tailwind's min-h-screen) is not enough: in Safari the + flex wrapper then does NOT grow to fit the panel, the panel overflows visibly + ("card geht aus dem Bild") but the container reports no overflow — so nothing + scrolls and the Save button is unreachable. A definite height + overflow + forces a real scroll container in every browser. The panel keeps margin:auto + so a SHORT modal stays centered, while a tall one starts at the top (no + top-clip) and scrolls to the bottom. -webkit-overflow-scrolling gives older + iOS momentum touch scrolling. */ .fixed.inset-0 { - overflow-y: auto !important; + overflow: hidden !important; } .fixed.inset-0 > .min-h-screen { - min-height: 100vh; + height: 100vh !important; + min-height: 0 !important; + overflow-y: auto !important; + -webkit-overflow-scrolling: touch; align-items: flex-start !important; } .fixed.inset-0 > .min-h-screen > .max-w-lg, diff --git a/server.js b/server.js index cba9e65..e5d6ee5 100644 --- a/server.js +++ b/server.js @@ -158,6 +158,18 @@ app.use('/api/indeed-import', (req, res, next) => { // Set EJS as template engine app.set('view engine', 'ejs'); + +// Cache-busting-Version für styles.css: die mtime der Datei beim Start. Wirkt +// nur als Query-Parameter am , also nach jedem Deploy (neuer +// Container → neue mtime → neue URL) erzwingt sie einen echten NeuDownload — +// "no-cache" allein reicht manchmal nicht, wenn ein Browser die alte Datei +// hart zwischengespeichert hat. Innerhalb eines Laufs bleibt der Wert stabil. +try { + const cssStat = fs.statSync(path.join(__dirname, 'public', 'css', 'styles.css')); + app.locals.assetVersion = String(cssStat.mtimeMs || Date.now()); +} catch (e) { + app.locals.assetVersion = String(Date.now()); +} app.set('views', path.join(__dirname, 'views')); // --------------------------------------------------------------------------- diff --git a/views/partials/head.ejs b/views/partials/head.ejs index b885faf..f2cb12a 100644 --- a/views/partials/head.ejs +++ b/views/partials/head.ejs @@ -20,4 +20,4 @@ tailwind.config = { darkMode: 'class' }; - +