fix(dashboard): don't fight user pinch-zoom in viewport override
visualViewport.resize fires on pinch-zoom, not just window-size change. The previous viewport-override would re-assert initial-scale=1.0 on every pinch event, snapping the user's zoom back to 1.0 instantly. Restrict the listener to orientationchange + initial settle timers so pinch-zoom is left alone after page load. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,46 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
<meta name="viewport" id="viewport-meta" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
||||||
|
<script>
|
||||||
|
// Android Chrome (multi-window, split-screen, freeform, certain WebView
|
||||||
|
// configs) can cache device-width at a smaller value than the actual
|
||||||
|
// window, leaving the page rendered into a small upper-left canvas
|
||||||
|
// while position:fixed elements pin to the much larger visual viewport.
|
||||||
|
// window.innerWidth returns the (broken) layout viewport, so re-asserting
|
||||||
|
// width=innerWidth changes nothing. visualViewport.width returns the
|
||||||
|
// actual window — re-assert against that on resize/orientation so Chrome
|
||||||
|
// recomputes the layout at the correct size.
|
||||||
|
(function () {
|
||||||
|
var meta = document.getElementById('viewport-meta');
|
||||||
|
if (!meta || typeof window === 'undefined') return;
|
||||||
|
var apply = function () {
|
||||||
|
var vv = window.visualViewport;
|
||||||
|
if (!vv) return;
|
||||||
|
var w = Math.round(vv.width);
|
||||||
|
var inner = window.innerWidth;
|
||||||
|
// Only override when layout viewport is meaningfully smaller than
|
||||||
|
// the visual viewport (the bug we're fixing). Otherwise keep the
|
||||||
|
// standard `width=device-width` so phones with the keyboard up etc.
|
||||||
|
// behave normally.
|
||||||
|
if (w > inner + 8) {
|
||||||
|
meta.setAttribute('content', 'width=' + w + ', initial-scale=1.0, viewport-fit=cover');
|
||||||
|
} else {
|
||||||
|
meta.setAttribute('content', 'width=device-width, initial-scale=1.0, viewport-fit=cover');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Only fire on events that genuinely change the window — NOT on
|
||||||
|
// visualViewport.resize, which also fires on pinch-zoom and would
|
||||||
|
// snap the user's zoom back to 1.0 every gesture.
|
||||||
|
window.addEventListener('orientationchange', apply);
|
||||||
|
apply();
|
||||||
|
// Re-check shortly after load — Chrome's initial reading sometimes
|
||||||
|
// settles a frame or two later in multi-window.
|
||||||
|
setTimeout(apply, 100);
|
||||||
|
setTimeout(apply, 500);
|
||||||
|
setTimeout(apply, 1500);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
<script>
|
<script>
|
||||||
// Append ?vpdebug to the URL to show a fixed overlay with the live
|
// Append ?vpdebug to the URL to show a fixed overlay with the live
|
||||||
// viewport / element dimensions. Diagnostic only — remove once the
|
// viewport / element dimensions. Diagnostic only — remove once the
|
||||||
@@ -22,8 +61,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
var tick = 0;
|
||||||
var update = function () {
|
var update = function () {
|
||||||
ensureAttached();
|
ensureAttached();
|
||||||
|
tick += 1;
|
||||||
var f = function (el) {
|
var f = function (el) {
|
||||||
if (!el) return 'none';
|
if (!el) return 'none';
|
||||||
var r = el.getBoundingClientRect();
|
var r = el.getBoundingClientRect();
|
||||||
@@ -55,8 +96,14 @@
|
|||||||
'pcCls ' + pcCls + '\n' +
|
'pcCls ' + pcCls + '\n' +
|
||||||
'mq768 ' + window.matchMedia('(max-width: 768px)').matches + '\n' +
|
'mq768 ' + window.matchMedia('(max-width: 768px)').matches + '\n' +
|
||||||
'dialogs ' + dialogs + ' focus ' + focused + '\n' +
|
'dialogs ' + dialogs + ' focus ' + focused + '\n' +
|
||||||
'sx ' + window.scrollX + ' sy ' + window.scrollY + '\n' +
|
'sx ' + window.scrollX + ' sy ' + window.scrollY + ' tick ' + tick + '\n' +
|
||||||
|
'docCW ' + document.documentElement.clientWidth + ' bodyCW ' + document.body.clientWidth + '\n' +
|
||||||
|
'docSW ' + document.documentElement.scrollWidth + ' bodySW ' + document.body.scrollWidth + '\n' +
|
||||||
'ua ' + (navigator.userAgent || '').slice(0, 80);
|
'ua ' + (navigator.userAgent || '').slice(0, 80);
|
||||||
|
try {
|
||||||
|
localStorage.setItem('vpdebug:last', box.textContent);
|
||||||
|
localStorage.setItem('vpdebug:lastAt', String(Date.now()));
|
||||||
|
} catch (e) {}
|
||||||
};
|
};
|
||||||
var attach = function () {
|
var attach = function () {
|
||||||
if (!document.body) {
|
if (!document.body) {
|
||||||
|
|||||||
Reference in New Issue
Block a user