Fix iOS Safari zoom-in on lock/unlock
Adds a tiny client component mounted in the root layout that listens for pageshow with persisted=true (bfcache resume) and nudges scroll + forces a reflow. Resolves the zoom-desync bug where viewportFit=cover + maximumScale=1 leaves the visual viewport stale after device lock. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
cd1fd6ad64
commit
9681dddc2e
@ -2,6 +2,7 @@ import type { Metadata, Viewport } from "next";
|
|||||||
import { Geist } from "next/font/google";
|
import { Geist } from "next/font/google";
|
||||||
import { Header } from "@/components/Header";
|
import { Header } from "@/components/Header";
|
||||||
import { BottomNav } from "@/components/BottomNav";
|
import { BottomNav } from "@/components/BottomNav";
|
||||||
|
import { ViewportRedrawOnResume } from "@/components/ViewportRedrawOnResume";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
|
||||||
const geistSans = Geist({
|
const geistSans = Geist({
|
||||||
@ -48,6 +49,7 @@ export default function RootLayout({
|
|||||||
suppressHydrationWarning
|
suppressHydrationWarning
|
||||||
>
|
>
|
||||||
<body className="min-h-dvh flex flex-col bg-background text-foreground">
|
<body className="min-h-dvh flex flex-col bg-background text-foreground">
|
||||||
|
<ViewportRedrawOnResume />
|
||||||
<Header />
|
<Header />
|
||||||
<main className="flex-1 bg-background">{children}</main>
|
<main className="flex-1 bg-background">{children}</main>
|
||||||
<BottomNav />
|
<BottomNav />
|
||||||
|
|||||||
20
components/ViewportRedrawOnResume.tsx
Normal file
20
components/ViewportRedrawOnResume.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
// iOS Safari bug: with viewportFit=cover + maximumScale=1, restoring from
|
||||||
|
// bfcache after lock/unlock can leave the visual viewport in a stale
|
||||||
|
// "zoomed" state. Nudging scroll + forcing a reflow on pageshow
|
||||||
|
// (persisted) realigns it without changing the zoom level.
|
||||||
|
export function ViewportRedrawOnResume() {
|
||||||
|
useEffect(() => {
|
||||||
|
const onShow = (e: PageTransitionEvent) => {
|
||||||
|
if (!e.persisted) return;
|
||||||
|
window.scrollTo(window.scrollX, window.scrollY);
|
||||||
|
void document.body.offsetHeight;
|
||||||
|
};
|
||||||
|
window.addEventListener("pageshow", onShow);
|
||||||
|
return () => window.removeEventListener("pageshow", onShow);
|
||||||
|
}, []);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user