Skip to content

Commit 1a6f237

Browse files
Fix iframe sizing to use actual content dimensions (#57)
The previous approach measured html/body elements which expand to fill the viewport, causing the iframe to be larger than necessary. Fix by using CSS fit-content to measure the true minimum content size: - Temporarily set html to fit-content to shrink it to content - This automatically includes body margins - Cache last sent size to prevent feedback loops from style changes - Simplify scrollbar compensation (already 0 when no scrollbar) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <[email protected]>
1 parent cf4492d commit 1a6f237

File tree

1 file changed

+28
-12
lines changed

1 file changed

+28
-12
lines changed

src/app.ts

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,8 @@ export class App extends Protocol<Request, Notification, Result> {
745745
*/
746746
setupSizeChangeNotifications() {
747747
let scheduled = false;
748+
let lastWidth = 0;
749+
let lastHeight = 0;
748750

749751
const sendBodySizeChange = () => {
750752
if (scheduled) {
@@ -753,18 +755,32 @@ export class App extends Protocol<Request, Notification, Result> {
753755
scheduled = true;
754756
requestAnimationFrame(() => {
755757
scheduled = false;
756-
const el = document.body.parentElement ?? document.body;
757-
const rect = el.getBoundingClientRect();
758-
// Compensate for viewport scrollbar on Linux/Windows where scrollbars
759-
// consume space. window.innerWidth includes scrollbar, clientWidth excludes it.
760-
const scrollbarWidth =
761-
window.innerWidth - document.documentElement.clientWidth;
762-
// Use max of rect (includes CSS transforms) and scroll dimensions (content overflow).
763-
const width = Math.ceil(
764-
Math.max(rect.width, el.scrollWidth) + scrollbarWidth,
765-
);
766-
const height = Math.ceil(Math.max(rect.height, el.scrollHeight));
767-
this.sendSizeChange({ width, height });
758+
const html = document.documentElement;
759+
760+
// Measure actual content size by temporarily setting html to fit-content.
761+
// This shrinks html to fit body (including body margins), giving us the
762+
// true minimum size needed by the content.
763+
const originalWidth = html.style.width;
764+
const originalHeight = html.style.height;
765+
html.style.width = "fit-content";
766+
html.style.height = "fit-content";
767+
const rect = html.getBoundingClientRect();
768+
html.style.width = originalWidth;
769+
html.style.height = originalHeight;
770+
771+
// Compensate for scrollbar width on Linux/Windows where scrollbars consume space.
772+
// On systems with overlay scrollbars (macOS), this will be 0.
773+
const scrollbarWidth = window.innerWidth - html.clientWidth;
774+
775+
const width = Math.ceil(rect.width + scrollbarWidth);
776+
const height = Math.ceil(rect.height);
777+
778+
// Only send if size actually changed (prevents feedback loops from style changes)
779+
if (width !== lastWidth || height !== lastHeight) {
780+
lastWidth = width;
781+
lastHeight = height;
782+
this.sendSizeChange({ width, height });
783+
}
768784
});
769785
};
770786

0 commit comments

Comments
 (0)