fix(layout): center fixed modals above the on-screen keyboard on Android (#4091)

Adds `interactive-widget=resizes-content` to the viewport meta. iOS
Safari already shrinks the layout viewport when the keyboard opens,
so existing `fixed inset-0` flex-centered modals (PassphrasePrompt,
GroupingModal, etc.) auto-center in the visible space. Android
Chrome defaults to `resizes-visual` — only the visual viewport
shrinks, layout stays full-height — leaving those modals rendered
under the keyboard. Switching to `resizes-content` makes Android
match iOS without any per-modal JS.

Updates both the App Router viewport export (src/app/layout.tsx)
and the Pages Router fallback meta (src/pages/_app.tsx).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Huang Xin
2026-05-08 20:31:37 +08:00
committed by GitHub
parent 712d564e9d
commit dc58d985e7
2 changed files with 17 additions and 1 deletions
+9
View File
@@ -67,6 +67,15 @@ export const viewport: Viewport = {
maximumScale: 1,
userScalable: false,
viewportFit: 'cover',
// Make Android Chrome's layout viewport shrink when the on-screen
// keyboard opens (matches iOS behavior). Without this, Android's
// default `interactive-widget=resizes-visual` keeps the layout
// viewport at full screen height while only the visual viewport
// shrinks — causing fixed `inset-0`-centered modals (passphrase
// prompt, group picker, etc.) to render under the keyboard. With
// `resizes-content`, `100vh` / flex centering naturally targets
// the available space above the keyboard.
interactiveWidget: 'resizes-content',
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
+8 -1
View File
@@ -9,9 +9,16 @@ function MyApp({ Component, pageProps }: AppProps) {
return (
<>
<Head>
{/*
* `interactive-widget=resizes-content` makes Android Chrome
* shrink the layout viewport when the on-screen keyboard
* opens (matches iOS default behavior). Without it, the
* layout viewport stays full-height and `fixed inset-0`-
* centered modals render under the keyboard.
*/}
<meta
name='viewport'
content='minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no, user-scalable=no, viewport-fit=cover'
content='minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no, user-scalable=no, viewport-fit=cover, interactive-widget=resizes-content'
/>
<meta name='application-name' content='Readest' />
<meta name='apple-mobile-web-app-capable' content='yes' />