the preview measures the page with its minimum height off
The site's shell is min-h-dvh so a short page puts its footer at the bottom of the window. Measuring it then asks the frame how tall the frame is, and the answer is whatever it already was. So the minimum is neutralised by a stylesheet injected into the frame, and what is left is the height of what is on the page. The cost, stated: the preview does not show a footer pushed to the bottom of a window, because it is not a window. It shows the page ending where it ends. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+24
-7
@@ -271,22 +271,36 @@ export const SitePreview = ({
|
||||
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 WRAPPER, with its minimum height taken off ──
|
||||
|
||||
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.
|
||||
The site's `<body>` is `min-h-screen` and the page shell inside it is `min-h-dvh`, so measuring
|
||||
either asks the frame how tall the frame is and the answer is whatever it already was. Both are
|
||||
right on a real page — a short one should put its footer at the bottom of the window — and both
|
||||
make this circular.
|
||||
|
||||
So the minimum is neutralised in the frame before measuring, by a stylesheet this injects. What is
|
||||
left is the height of what is actually on the page, which is what the panel should be.
|
||||
|
||||
The cost, stated: the preview does not show the footer pushed to the bottom of a window, because it
|
||||
is not a window. It shows the page ending where the page ends.
|
||||
*/
|
||||
const [contentHeight, setContentHeight] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (!loaded) return;
|
||||
const frameDocument = frame.current?.contentDocument;
|
||||
const page = frameDocument?.body.firstElementChild as HTMLElement | null;
|
||||
const page = frameDocument?.querySelector<HTMLElement>('[data-page-shell]') ?? (frameDocument?.body.firstElementChild as HTMLElement | null);
|
||||
const view = frameDocument?.defaultView;
|
||||
if (!page || !view) return;
|
||||
|
||||
/*
|
||||
Injected rather than set inline: `min-h-dvh` is a class, and an inline `min-height` would have to
|
||||
win against it by specificity. A stylesheet of our own, last in the document, does.
|
||||
*/
|
||||
const relax = frameDocument!.createElement('style');
|
||||
relax.textContent = '[data-page-shell]{min-height:0!important}body{min-height:0!important}';
|
||||
frameDocument!.head.append(relax);
|
||||
|
||||
const measure = () => setContentHeight(Math.ceil(page.getBoundingClientRect().height));
|
||||
measure();
|
||||
|
||||
@@ -299,7 +313,10 @@ export const SitePreview = ({
|
||||
*/
|
||||
const observer = new view.ResizeObserver(measure);
|
||||
observer.observe(page);
|
||||
return () => observer.disconnect();
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
relax.remove();
|
||||
};
|
||||
}, [loaded]);
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user