the preview is as tall as the page
The frame took all the room the panel had, so a short page left a band of white under the footer with the measure guides running down through it. An iframe has no height: fit-content, so the page is measured inside it and the frame follows. The wrapper, not the body — body is min-h-screen, so measuring it would ask the frame how tall the frame is. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+44
-8
@@ -232,17 +232,53 @@ export const SitePreview = ({
|
||||
|
||||
|
||||
/*
|
||||
All the room there is. WIDTH is the device; height is just how much of the page you can see.
|
||||
The page's own height, measured inside the frame.
|
||||
|
||||
It was capped at the device's own height, on the reasoning that a 390x844 phone drawn 1200 pixels
|
||||
tall is not a phone. That was wrong, and the empty band under the preview was the tell: media
|
||||
queries answer WIDTH, so the layout at 390 is the phone's layout whatever the height. A taller frame
|
||||
shows more page, which is a scroll position rather than a different device.
|
||||
── Why it is measured and not just "the room" ──
|
||||
|
||||
One real consequence, and it is the right one: the footer is `min-h-dvh`, so it sits at the bottom
|
||||
of the FRAME. A taller frame therefore puts it lower — exactly as a taller browser window does.
|
||||
It was `available.height` — all the room the panel had — which is right for a page longer than the
|
||||
panel and wrong for every other one: a short page left a band of white below the footer with the
|
||||
measure guides running down through it. Nothing was broken; the frame was simply taller than the
|
||||
document, and an iframe has no `height: fit-content`.
|
||||
|
||||
── The WRAPPER, not the body ──
|
||||
|
||||
The site's `<body>` is `min-h-screen`, so its height is the FRAME's height and measuring it would
|
||||
ask the frame how tall the frame is. Its one child is the page — header, main, footer — and that is
|
||||
a real content height. It stopped being `min-h-dvh` on the same day this changed, for the same
|
||||
reason: the stretch belonged to nothing anybody could see or set.
|
||||
*/
|
||||
const shownHeight = Math.max(0, available.height);
|
||||
const [contentHeight, setContentHeight] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (!loaded) return;
|
||||
const frameDocument = frame.current?.contentDocument;
|
||||
const page = frameDocument?.body.firstElementChild as HTMLElement | null;
|
||||
const view = frameDocument?.defaultView;
|
||||
if (!page || !view) return;
|
||||
|
||||
const measure = () => setContentHeight(Math.ceil(page.getBoundingClientRect().height));
|
||||
measure();
|
||||
|
||||
/*
|
||||
Observed, because the page changes height without reloading: choosing a spacing rewrites classes
|
||||
in this document, and the device buttons reflow it at a new width.
|
||||
|
||||
No feedback loop — the frame's height is set from this, and the wrapper's height does not depend
|
||||
on the frame's.
|
||||
*/
|
||||
const observer = new view.ResizeObserver(measure);
|
||||
observer.observe(page);
|
||||
return () => observer.disconnect();
|
||||
}, [loaded]);
|
||||
|
||||
/*
|
||||
As tall as the page, or as tall as the room, whichever is less.
|
||||
|
||||
A long page still fills the panel and scrolls, exactly as it did. WIDTH is the device and height is
|
||||
not: media queries answer width, so the layout at 390 is the phone's layout whatever the height.
|
||||
*/
|
||||
const shownHeight = contentHeight ? Math.min(contentHeight, Math.max(0, available.height)) : Math.max(0, available.height);
|
||||
|
||||
/*
|
||||
When the frame is wider than the room, show its MIDDLE.
|
||||
|
||||
Reference in New Issue
Block a user