UX: Only lock viewport scale during focusin events for iOS PWA/Hub (#30908)

c171e3dc works well in Safari, because the browser ignores the
`user-scalable=no` directive. However, PWA/Hub do respect the directive,
which means that it stopped pinch-zooming from working.

This commit updates the strategy for those environments so that the
viewport is only locked briefly during a focusin event. The simpler
strategy is maintained for the real safari browser.
This commit is contained in:
David Taylor
2025-01-21 22:19:59 +00:00
committed by GitHub
parent 8c31f1aa5f
commit d7f008d482

View File

@ -14,11 +14,6 @@ export default {
}
let value = viewport.getAttribute("content");
if (caps.isIOS) {
// In iOS Safari, setting user-scalable=no doesn't actually prevent the user from zooming in.
// But, it does prevent the annoying 'auto zoom' when focussing input fields with small font-sizes.
value += ", user-scalable=no";
}
if (!caps.isSafari) {
// Safari prints a big red warning because it doesn't support this property.
@ -26,6 +21,39 @@ export default {
value += ", interactive-widget=resizes-content";
}
if (caps.isIOS) {
// iOS 'auto-zooms' into inputs with font sizes smaller than 16px. To prevent this,
// we use two different strategies.
if (caps.isiOSPWA || caps.isAppWebview) {
// For PWA/Hub, we lock the viewport zoom temporarily during `focusin` events.
// Unfortunately this doesn't catch the case when an input is already autofocussed, but the
// keyboard isn't open yet. But it's better than nothing.
this.lockViewportDuringFocus(viewport, value);
} else {
// In the full Safari browser, user-scalable=no doesn't actually prevent the user from zooming in.
// So we can keep it in place all the time to prevent the auto-zoom.
value += ", user-scalable=no";
}
}
viewport.setAttribute("content", value);
},
lockViewportDuringFocus(viewport, initialValue) {
let timer;
window.addEventListener("focusin", (event) => {
if (!["INPUT", "TEXTAREA"].includes(event.target.tagName)) {
return;
}
viewport.setAttribute("content", `${initialValue}, user-scalable=no`);
clearTimeout(timer);
timer = setTimeout(
() => viewport.setAttribute("content", initialValue),
100
);
});
},
};