Skip to content

fix(detail): portal fullscreen viewer to body so modal zoom isn't blank#531

Closed
Zheaoli wants to merge 1 commit into
mainfrom
fix/fullscreen-viewer-portal
Closed

fix(detail): portal fullscreen viewer to body so modal zoom isn't blank#531
Zheaoli wants to merge 1 commit into
mainfrom
fix/fullscreen-viewer-portal

Conversation

@Zheaoli

@Zheaoli Zheaoli commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Symptom

Opening a photo's fullscreen zoom from the intercepted-route modal (album grid → detail) shows a blank screen. The same photo opened via a direct /preview/<id> link works fine.

Root cause

The fullscreen overlay (components/album/progressive-image.tsx) uses position: fixed; inset: 0. In the modal, it is a descendant of Radix DialogContent, whose class includes translate-x-[-50%] translate-y-[-50%] (plus a zoom-in-95 open animation). A transformed ancestor establishes the containing block for position: fixed descendants, so the viewer was positioned relative to the dialog box rather than the viewport → it never covered the screen → blank.

The full-page /preview/<id> route has no transformed ancestor, which is exactly why that path worked.

(GPU-independent — the viewer mounts; it's just mispositioned/clipped. The earlier "View fullscreen toolbar button" mount-gate fix, #528, is a separate issue on a different path.)

Fix

Render the overlay through createPortal(..., document.body) so its fixed positioning is always relative to the viewport, independent of any transformed ancestor. Guarded with typeof document !== 'undefined' for SSR.

  • The overlay stays in the React tree (portals preserve it), so the keep-mounted lifecycle + WebGL viewer teardown from the LRU work are unchanged.
  • The modal wrapper already prevents interact-outside dismissal (onInteractOutsidepreventDefault), so portaling the viewer out of DialogContent doesn't let zoom gestures close the dialog.
  • z-[100] keeps the viewer above the dialog z-50 (both at body level after portal).

Verify

After deploy: album grid → open a photo (modal) → click the photo / "View fullscreen" → the zoomable image should now fill the viewport (previously blank). Direct /preview/<id> should remain unaffected. Devtools: the overlay's boundingClientRect should be 0,0,vw,vh, not trapped in the dialog box.

(Headless note: the intercepted-route modal can't be reproduced in headless — synthetic clicks fall through to the full-page route — so the modal-path verification needs a real browser / Manjusaka.)

… blank

Opening a photo's fullscreen zoom from the intercepted-route modal (grid →
detail) showed a blank screen, while the same photo opened via a direct
/preview/<id> link worked. Root cause: the fullscreen overlay uses
`position: fixed; inset: 0`, but in the modal it is a descendant of Radix
`DialogContent`, whose `translate-x-[-50%] translate-y-[-50%]` (+ zoom-in)
transform establishes a containing block for fixed-positioned descendants.
So the viewer was positioned relative to the dialog box instead of the
viewport and never covered the screen → blank. The full-page route has no
such transformed ancestor, which is why it worked.

Render the overlay through `createPortal(..., document.body)` so its
`fixed` positioning is always relative to the viewport, regardless of any
transformed ancestor. Guarded with `typeof document !== 'undefined'` for
SSR. The overlay stays in the React tree (portals preserve it), so the
keep-mounted lifecycle and WebGL viewer teardown from the LRU work are
unchanged. The dialog already prevents interact-outside dismissal
(`onInteractOutside` preventDefault in the modal wrapper), so viewer
gestures don't close it; viewer `z-[100]` stays above the dialog `z-50`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
picimpact Building Building Preview, Comment Jun 11, 2026 9:29am

@Zheaoli

Zheaoli commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator Author

Closing in favor of #530 (identical portal-to-body fix, already ready). Duplicate from a claim collision — using #530.

@Zheaoli Zheaoli closed this Jun 11, 2026
@Zheaoli Zheaoli deleted the fix/fullscreen-viewer-portal branch June 11, 2026 09:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant