Keep the whole photo on screen after leaving fullscreen on iPad - #384
Merged
Conversation
PR #382 pulled the bottom panels back into the visible area after iPadOS strands the layout viewport at its fullscreen size, but the photo itself has the same problem: the swiper container and slide images are sized with 100dvh, which resolves against that same stranded layout viewport. After leaving fullscreen the bottom ~40px of the image — the height of the returning browser chrome — hangs off the bottom of the tablet, and neither pinch nor rotation brings it back. Only landscape shows it, because that is the orientation in which a contain-fit photo actually touches the top and bottom edges; in portrait the loss falls inside the letterbox bars. panel-anchor.js already measures the overshoot; it now also publishes the visible height as a --visible-viewport-height custom property on the root element, and the three 100dvh sizing rules in swiper.css consume it with 100dvh as the fallback. Where the viewports agree the property is never set and the CSS behaves exactly as before. Swiper notices the container resize through its default ResizeObserver, so no explicit update call is needed. Sizing the photo by the correction raises the stakes on two moments where the sync previously misfired against the small panels and now would visibly bounce the whole image, so both hold the current correction instead of recomputing: - The blur edge of a text field. On iPad the blur arrives while the software keyboard is still fully on screen — hiding the search panel blurs its input first, the keyboard collapses after — so the first resyncs after blur read the keyboard as a ~360px overshoot. The hold now extends from focus until 700ms past blur, and the expiry resamples the truth. - Pinch-zoom. Clearing the correction the moment scale crosses 1.01 grew the container back to the stranded 100dvh under the user's fingers (and dropped the panels back off-screen). The overshoot has not gone away because the user zoomed, so it is held; zoom-out resyncs via the viewport resize. Holding instead of recomputing also stops a rotate-with-keyboard-up from publishing a height that mixes the held overshoot with a fresh clientHeight. Not touched: grid view sizes its rows from window.innerHeight and recomputes only on its own events, so it still under-shows the bottom row on a stranded viewport — a follow-up, not part of this fix. The 100vh modals are centered and unaffected in practice. Tests: panel-anchor.test.js covers the property being published with the correction, staying unset when the viewports agree, clearing when they re-converge, the keyboard hold across focus, blur edge and collapse, the pinch hold and its release, and the rotate-with-keyboard case. Frontend 665 passed, lint and format clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KLxwVusSvKkfdJS3g9QbB9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
On iPad Chrome, viewing an image in swiper mode, entering fullscreen and returning to windowed mode cuts ~40px off the bottom of the photo, and neither pinch nor rotating the tablet brings it back. It only shows in landscape.
Why
Same disease #382 fixed for the bottom panels: iPadOS keeps the layout viewport stranded at its fullscreen size after the exit. #382 translated the panels back into view, but the swiper container and slide images are sized with
100dvh— which resolves against that same stranded viewport — so the bottom ~40px (the returning browser chrome's height) of the photo hangs off the tablet. Landscape is the orientation where the contain-fit photo actually touches the top and bottom edges; in portrait the loss falls inside the letterbox bars, which is why it looked landscape-only.The fix
panel-anchor.jsalready measures the overshoot (with the keyboard hold, pinch guard, chrome-height floor, and settle resample). It now also publishes the visible height as a--visible-viewport-heightcustom property on the root element, and the three100dvhrules inswiper.cssconsume it with100dvhas fallback. Where the viewports agree the property is never set and nothing changes. Swiper picks up the container resize through its default ResizeObserver.An adversarial review of the first cut found two moments where the sync recomputed when it must not — previously they only twitched the small panels, but sizing the photo by the correction would have made them a visible full-image bounce. Both now hold the current correction instead of recomputing:
Holding rather than recomputing also stops a rotate-with-the-keyboard-up from publishing a height that mixes the held overshoot with a fresh
clientHeight.Known follow-up, deliberately not in this PR: grid view sizes its rows from
window.innerHeightand would still under-show the bottom row on a stranded viewport.Tests
panel-anchor.test.js: property published with the correction, unset when the viewports agree, cleared when they re-converge, the keyboard hold across focus / blur edge / collapse, the pinch hold and release, and the rotate-with-keyboard case. Frontend 665 passed, lint and format clean.Needs on-device verification on the reporter's iPad (Chrome, landscape): fullscreen → windowed with a landscape photo, then text search open/submit, and pinch-zoom while stranded.
🤖 Generated with Claude Code
https://claude.ai/code/session_01KLxwVusSvKkfdJS3g9QbB9