Modal-Scroll: Wrapper als definite-height Scroll-Container (Safari-safe)

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=<mtime>) am <link>, damit ein
hart zwischengespeichertes altes Stylesheet nach einem Deploy garantiert
neu geladen wird.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-07-20 09:14:12 +02:00
co-authored by Claude
parent 811188f492
commit a6a2fabf05
3 changed files with 28 additions and 12 deletions
+15 -11
View File
@@ -452,20 +452,24 @@ button.loading::after {
============================================ */
/* Modals: the overlay locks body scroll (overflow:hidden on <body>), 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,
+12
View File
@@ -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 <link href>, 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'));
// ---------------------------------------------------------------------------
+1 -1
View File
@@ -20,4 +20,4 @@
tailwind.config = { darkMode: 'class' };
</script>
<!-- Custom CSS -->
<link rel="stylesheet" href="/css/styles.css">
<link rel="stylesheet" href="/css/styles.css?v=<%= assetVersion %>">