fix: resolve iOS PWA bottom space and keyboard zoom issues
- pwa.css: body::after now uses var(--glass-bg) matching the nav's glass background exactly; z-index lowered to z-nav-1 so the nav renders on top in the overlap area (safe-area padding), removing the visible color mismatch that appeared as empty space - router.js: add iOS focusin/focusout handlers that temporarily set maximum-scale=1 on input focus to prevent WKWebView auto-zoom; restores original viewport content 150ms after blur so manual zoom remains available for accessibility
This commit is contained in:
@@ -589,6 +589,38 @@ if (window.visualViewport) {
|
||||
});
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
// iOS PWA: Viewport-Zoom bei Tastatur-Erscheinen verhindern.
|
||||
// iOS Safari/WKWebView zoomt ins Layout wenn ein Formularfeld fokussiert wird
|
||||
// und stellt den Zoom nach Tastatur-Schliessen im Standalone-Modus nicht
|
||||
// automatisch zurück → Menüpunkte verschwinden aus dem sichtbaren Bereich.
|
||||
//
|
||||
// Fix: maximum-scale=1 während des Focus setzt (verhindert Zoom),
|
||||
// danach original Wert wiederherstellen (erhält manuelle Zoom-Möglichkeit
|
||||
// für Barrierefreiheit). Nur auf iOS-Geräten aktiv.
|
||||
// --------------------------------------------------------
|
||||
if (/iPhone|iPad|iPod/.test(navigator.userAgent)) {
|
||||
const metaViewport = document.querySelector('meta[name="viewport"]');
|
||||
if (metaViewport) {
|
||||
const originalContent = metaViewport.getAttribute('content');
|
||||
const noZoomContent = originalContent.replace(/maximum-scale=\d+/, 'maximum-scale=1');
|
||||
|
||||
document.addEventListener('focusin', ({ target }) => {
|
||||
if (['INPUT', 'TEXTAREA', 'SELECT'].includes(target.tagName)) {
|
||||
metaViewport.setAttribute('content', noZoomContent);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('focusout', ({ target }) => {
|
||||
if (['INPUT', 'TEXTAREA', 'SELECT'].includes(target.tagName)) {
|
||||
// Kurze Verzögerung: iOS braucht ~150ms um Layout nach Tastatur-
|
||||
// Schliessen wiederherzustellen, bevor scale zurückgesetzt wird.
|
||||
setTimeout(() => metaViewport.setAttribute('content', originalContent), 150);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Initialisierung
|
||||
// --------------------------------------------------------
|
||||
|
||||
@@ -79,8 +79,11 @@ nav,
|
||||
|
||||
/* iOS PWA: Schwarzen Streifen unter der Nav verhindern.
|
||||
* iOS reserviert den Home-Indicator-Bereich unterhalb des CSS-Viewports.
|
||||
* Das ::after-Element bekommt denselben Blur+Hintergrund wie .nav-bottom,
|
||||
* damit kein Farbunterschied zwischen Nav-Bar und Safe-Area-Bereich entsteht. */
|
||||
* body::after füllt diesen Bereich mit dem gleichen Glass-Hintergrund wie die Nav.
|
||||
* z-index: z-nav - 1 (unter der Nav) - dadurch rendert die Nav immer oben.
|
||||
* Im Überlappungsbereich (Nav-Padding = Safe-Area) liegt die Nav darüber;
|
||||
* in einem eventuellen Spalt zwischen Nav-Unterkante und Displayrand liegt
|
||||
* body::after sichtbar - optisch identisch mit der Nav. */
|
||||
body::after {
|
||||
content: '';
|
||||
position: fixed;
|
||||
@@ -88,9 +91,9 @@ nav,
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: env(safe-area-inset-bottom, 0px);
|
||||
background-color: color-mix(in srgb, var(--color-surface) 85%, transparent);
|
||||
backdrop-filter: blur(16px) saturate(180%);
|
||||
-webkit-backdrop-filter: blur(16px) saturate(180%);
|
||||
z-index: var(--z-nav);
|
||||
background-color: var(--glass-bg);
|
||||
backdrop-filter: var(--blur-md) saturate(180%);
|
||||
-webkit-backdrop-filter: var(--blur-md) saturate(180%);
|
||||
z-index: calc(var(--z-nav) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user