iOS viewport zoom-reset on form-field exit — global IIFE in base.html

iOS Safari auto-zooms when a user taps an `<input>`/`<textarea>`/`<select>` whose font-size is < 16px, and does NOT auto-zoom back out on blur — the page stays zoomed even after the field loses focus. New ~10-line IIFE at base.html slots next to the existing h2-letter-splitter at the bottom of <body>: caches the page's `<meta name="viewport">` content, listens (document-level, bubbling `focusout`) for inputs leaving focus, then briefly appends `, maximum-scale=1.0` before reverting 100ms later — iOS reads the tightened constraint as a "zoom violation" and snaps the viewport back to 1:1, after which the revert frees the user to pinch-zoom manually anywhere else on the page ; chose `focusout` over `blur`+capture-phase since focusout bubbles natively (cleaner); skips if `.matches` isn't available (defensive for older browsers); skips silently if no viewport meta is present (defensive) ; no test layer — iOS-specific behavior that's awkward to FT (would need a real iOS Safari runner; Selenium+Firefox doesn't replicate the auto-zoom). Verified no conflict w. other focusout listeners (grep: only vendor JS — d3 / htmx / jquery / select2 — none of which listen at document scope on inputs/textareas/selects). Side-track addition between Sprint 1 (table hex layout fbe6c12... well, 7165974) and Sprint 2 (My Sea applet kickoff) per user ask

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-05-18 18:22:08 -04:00
parent 7165974905
commit 8066ac289f

View File

@@ -98,6 +98,22 @@
}
}
}());
// iOS Safari auto-zooms when focusing an <input>/<textarea>/<select>
// whose font-size is < 16px, and does NOT auto-zoom back out on blur.
// Briefly toggling maximum-scale=1.0 on the viewport meta forces iOS to
// reset to 1:1; reverting after 100ms restores the default content so
// users can still pinch-zoom manually elsewhere on the page.
(function () {
var vp = document.querySelector('meta[name="viewport"]');
if (!vp) return;
var base = vp.getAttribute('content');
document.addEventListener('focusout', function (e) {
if (!e.target.matches || !e.target.matches('input, textarea, select')) return;
vp.setAttribute('content', base + ', maximum-scale=1.0');
setTimeout(function () { vp.setAttribute('content', base); }, 100);
});
}());
</script>
<script>
(function () {