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
|
── Why it is measured and not just "the room" ──
|
||||||
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.
|
|
||||||
|
|
||||||
One real consequence, and it is the right one: the footer is `min-h-dvh`, so it sits at the bottom
|
It was `available.height` — all the room the panel had — which is right for a page longer than the
|
||||||
of the FRAME. A taller frame therefore puts it lower — exactly as a taller browser window does.
|
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.
|
When the frame is wider than the room, show its MIDDLE.
|
||||||
|
|||||||
Reference in New Issue
Block a user