On Android the soft keyboard overlaid the layout viewport and the browser auto-scrolled the document on focus, dragging the shell (and its special-key bar) to the top of the screen and forcing a manual scroll. - index.html: interactive-widget=resizes-content so Chrome resizes the layout viewport instead of overlaying the keyboard, killing the auto-scroll. - viewport.ts: mirror visualViewport.offsetTop into --app-top for iOS / older browsers that ignore interactive-widget and still scroll under the keyboard. - styles.css: translateY(--app-top) re-pins #app to the visible region. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
|
||||
content="width=device-width, initial-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content"
|
||||
/>
|
||||
<meta name="color-scheme" content="dark light" />
|
||||
<meta name="theme-color" content="#1a1d24" media="(prefers-color-scheme: dark)" />
|
||||
|
||||
+4
-1
@@ -211,8 +211,11 @@ body {
|
||||
#app {
|
||||
/* `--app-vh` tracks the *visual* viewport (set by installViewportSizing) so
|
||||
the shell stays above the mobile soft keyboard; falls back to the layout
|
||||
viewport where `visualViewport` is unavailable. */
|
||||
viewport where `visualViewport` is unavailable. `--app-top` follows the
|
||||
layout viewport's scroll under the keyboard so the shell stays pinned to
|
||||
the visible region instead of drifting to the top. */
|
||||
height: var(--app-vh, 100%);
|
||||
transform: translateY(var(--app-top, 0px));
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
+12
-1
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Bind the app shell's height to the *visual* viewport.
|
||||
* Bind the app shell's height *and position* to the *visual* viewport.
|
||||
*
|
||||
* On mobile the layout viewport does not shrink when the on-screen keyboard
|
||||
* opens — only the visual viewport does. A shell sized at `height: 100%` (or
|
||||
@@ -8,6 +8,16 @@
|
||||
* `visualViewport.height` onto a CSS custom property keeps the shell exactly as
|
||||
* tall as the visible area, so the key bar lands just above the keyboard.
|
||||
*
|
||||
* Height alone isn't enough: when the keyboard opens the browser also scrolls
|
||||
* the layout viewport to reveal the focused element, which drags the shell
|
||||
* (anchored at layout-top) up and out of view — the key bar ends up at the top
|
||||
* of the screen and the user has to scroll back down. `visualViewport.offsetTop`
|
||||
* is how far the layout viewport has scrolled under the keyboard; translating
|
||||
* the shell down by that amount re-pins it to the visible region. (Chrome's
|
||||
* `interactive-widget=resizes-content`, set in the viewport meta, prevents the
|
||||
* scroll entirely on Android; this covers iOS and older browsers that ignore
|
||||
* it, where offsetTop stays non-zero.)
|
||||
*
|
||||
* No-ops where `visualViewport` is unavailable; the CSS falls back to `100%`.
|
||||
*/
|
||||
export function installViewportSizing(): void {
|
||||
@@ -20,6 +30,7 @@ export function installViewportSizing(): void {
|
||||
const sync = () => {
|
||||
raf = 0;
|
||||
root.style.setProperty("--app-vh", `${Math.round(vv.height)}px`);
|
||||
root.style.setProperty("--app-top", `${Math.round(vv.offsetTop)}px`);
|
||||
};
|
||||
const schedule = () => {
|
||||
if (raf) return;
|
||||
|
||||
Reference in New Issue
Block a user