iOS-Fixes: Zoom + Overlay-Verrutschen bei Tastatur-Öffnung behoben

- Viewport-Meta: maximum-scale=1.0 + viewport-fit=cover + user-scalable=no
  → verhindert Zoom beim Fokussieren von Input-Feldern auf iOS
- Input-Font-Size auf 16px (Chat + Submit-Formular)
  → iOS Safari zoomt nicht mehr rein (<16px trigger)
- Backdrop: height:100dvh für lückenlose Abdeckung
- visualViewport-Resize-Handler: Overlays werden bei iOS-Tastatur
  korrekt nach oben geschoben, kein seitliches Verrutschen mehr
This commit is contained in:
Hermes Agent
2026-06-19 20:17:06 +02:00
parent b458bfd5d4
commit 4c6baafa10
+44 -10
View File
@@ -2421,7 +2421,7 @@ def _get_user_from_session(db) -> dict | None:
# ── HTML-Templates (plain strings, no f-string needed) ────────────── # ── HTML-Templates (plain strings, no f-string needed) ──────────────
_REGISTER_TPL = """<!DOCTYPE html> _REGISTER_TPL = """<!DOCTYPE html>
<html lang="de"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"> <html lang="de"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover, user-scalable=no">
<title>Registrieren BSN Community</title> <title>Registrieren BSN Community</title>
<style> <style>
body{font-family:-apple-system,sans-serif;background:#1a1a2e;color:#eee;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0} body{font-family:-apple-system,sans-serif;background:#1a1a2e;color:#eee;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0}
@@ -2449,7 +2449,7 @@ input{width:100%;padding:0.8rem;margin:0.4rem 0;border-radius:8px;border:1px sol
</div></body></html>""" </div></body></html>"""
_LOGIN_TPL = """<!DOCTYPE html> _LOGIN_TPL = """<!DOCTYPE html>
<html lang="de"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"> <html lang="de"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover, user-scalable=no">
<title>Login BSN Community</title> <title>Login BSN Community</title>
<style> <style>
body{font-family:-apple-system,sans-serif;background:#1a1a2e;color:#eee;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0} body{font-family:-apple-system,sans-serif;background:#1a1a2e;color:#eee;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0}
@@ -2476,7 +2476,7 @@ input{width:100%;padding:0.8rem;margin:0.4rem 0;border-radius:8px;border:1px sol
</div></body></html>""" </div></body></html>"""
_PROFILE_TPL = """<!DOCTYPE html> _PROFILE_TPL = """<!DOCTYPE html>
<html lang="de"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"> <html lang="de"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover, user-scalable=no">
<title>Profil BSN Community</title> <title>Profil BSN Community</title>
<style> <style>
body{font-family:-apple-system,sans-serif;background:#1a1a2e;color:#eee;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0} body{font-family:-apple-system,sans-serif;background:#1a1a2e;color:#eee;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0}
@@ -2666,7 +2666,7 @@ def public_frontend():
empty_state = """<!DOCTYPE html> empty_state = """<!DOCTYPE html>
<html lang="de"> <html lang="de">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover, user-scalable=no">
<title>BSN Community Stimmen aus der Szene</title> <title>BSN Community Stimmen aus der Szene</title>
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@@ -2885,7 +2885,7 @@ def public_frontend():
return ("""<!DOCTYPE html> return ("""<!DOCTYPE html>
<html lang="de"> <html lang="de">
<head> <head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover, user-scalable=no">
<title>BSN Community Stimmen aus der Szene</title> <title>BSN Community Stimmen aus der Szene</title>
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@@ -3047,7 +3047,7 @@ def public_frontend():
background:#fff; border-radius:18px; box-shadow:0 12px 48px rgba(0,0,0,0.22); background:#fff; border-radius:18px; box-shadow:0 12px 48px rgba(0,0,0,0.22);
display:none; flex-direction:column; overflow:hidden; } display:none; flex-direction:column; overflow:hidden; }
.chat-overlay.open { display:flex; } .chat-overlay.open { display:flex; }
.chat-backdrop { position:fixed; inset:0; z-index:10000; background:rgba(0,0,0,0.25); backdrop-filter:blur(4px); -webkit-backdrop-filter:blur(4px); display:none; } .chat-backdrop { position:fixed; inset:0; z-index:10000; background:rgba(0,0,0,0.25); backdrop-filter:blur(4px); -webkit-backdrop-filter:blur(4px); display:none; height:100dvh; }
.chat-backdrop.open { display:block; } .chat-backdrop.open { display:block; }
.chat-header { background:#20228a; color:#fff; padding:0.9rem 1.2rem; .chat-header { background:#20228a; color:#fff; padding:0.9rem 1.2rem;
font-weight:700; font-size:0.9rem; display:flex; align-items:center; justify-content:space-between; } font-weight:700; font-size:0.9rem; display:flex; align-items:center; justify-content:space-between; }
@@ -3066,7 +3066,7 @@ def public_frontend():
@keyframes fadeUp { from{opacity:0;transform:translateY(8px);} to{opacity:1;transform:translateY(0);} } @keyframes fadeUp { from{opacity:0;transform:translateY(8px);} to{opacity:1;transform:translateY(0);} }
.chat-footer { padding:0.7rem 0.9rem; border-top:1px solid #eee; display:flex; gap:0.5rem; } .chat-footer { padding:0.7rem 0.9rem; border-top:1px solid #eee; display:flex; gap:0.5rem; }
.chat-footer input { flex:1; border:1.5px solid #ddd; border-radius:999px; .chat-footer input { flex:1; border:1.5px solid #ddd; border-radius:999px;
padding:0.55rem 1rem; font-size:0.82rem; font-family:inherit; outline:none; padding:0.55rem 1rem; font-size:16px; font-family:inherit; outline:none;
transition:border-color 0.15s; } transition:border-color 0.15s; }
.chat-footer input:focus { border-color:#20228a; } .chat-footer input:focus { border-color:#20228a; }
.chat-footer button { background:#20228a; color:#fff; border:none; border-radius:999px; .chat-footer button { background:#20228a; color:#fff; border:none; border-radius:999px;
@@ -3101,7 +3101,7 @@ def public_frontend():
text-transform:uppercase; letter-spacing:0.03em; margin-bottom:0.2rem; margin-top:0.8rem; } text-transform:uppercase; letter-spacing:0.03em; margin-bottom:0.2rem; margin-top:0.8rem; }
.submit-body label:first-of-type { margin-top:0; } .submit-body label:first-of-type { margin-top:0; }
.submit-body input, .submit-body textarea { width:100%; border:1.5px solid #ddd; .submit-body input, .submit-body textarea { width:100%; border:1.5px solid #ddd;
border-radius:10px; padding:0.55rem 0.8rem; font-size:0.82rem; font-family:inherit; border-radius:10px; padding:0.55rem 0.8rem; font-size:16px; font-family:inherit;
outline:none; transition:border-color 0.15s; } outline:none; transition:border-color 0.15s; }
.submit-body textarea { resize:vertical; min-height:70px; } .submit-body textarea { resize:vertical; min-height:70px; }
.submit-body input:focus, .submit-body textarea:focus { border-color:#20228a; } .submit-body input:focus, .submit-body textarea:focus { border-color:#20228a; }
@@ -3656,6 +3656,40 @@ def public_frontend():
})(); })();
</script> </script>
<script>
// iOS: Verhindert dass Overlays bei Tastatur-Öffnung aus dem Bild rutschen
// visualViewport API gleicht den Offset aus
(function() {
if (!window.visualViewport) return;
var chatO = document.getElementById('chatOverlay');
var submitO = document.getElementById('submitOverlay');
var backdrop = document.getElementById('chatBackdrop');
window.visualViewport.addEventListener('resize', function() {
var offsetTop = window.visualViewport.offsetTop || 0;
// Overlays und Backdrop nach oben schieben wenn Tastatur offen
if (chatO && chatO.classList.contains('open')) {
chatO.style.transform = 'translateY(-' + offsetTop + 'px)';
}
if (submitO && submitO.classList.contains('open')) {
submitO.style.transform = 'translateY(-' + offsetTop + 'px)';
}
});
// Reset transform wenn Overlay geschlossen wird
var obs = new MutationObserver(function() {
if (chatO && !chatO.classList.contains('open')) {
chatO.style.transform = '';
}
if (submitO && !submitO.classList.contains('open')) {
submitO.style.transform = '';
}
});
if (chatO) obs.observe(chatO, {attributes: true, attributeFilter: ['class']});
if (submitO) obs.observe(submitO, {attributes: true, attributeFilter: ['class']});
})();
</script>
</body> </body>
</html>""").replace("{LOGO_B64}", LOGO_B64) </html>""").replace("{LOGO_B64}", LOGO_B64)
@@ -3686,7 +3720,7 @@ def _legal_page(title, content_html):
return f"""<!DOCTYPE html> return f"""<!DOCTYPE html>
<html lang="de"> <html lang="de">
<head> <head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover, user-scalable=no">
<title>{title} BSN Community</title> <title>{title} BSN Community</title>
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@@ -4475,7 +4509,7 @@ def public_detail(sub_id: int):
return f"""<!DOCTYPE html> return f"""<!DOCTYPE html>
<html lang="de"> <html lang="de">
<head> <head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover, user-scalable=no">
<title>Beitrag BSN Community</title> <title>Beitrag BSN Community</title>
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>