From 23722f8b6d1637852d3fad7086c970a7524ca077 Mon Sep 17 00:00:00 2001 From: neodk2004 Date: Fri, 14 Aug 2026 15:14:32 +0200 Subject: [PATCH] fix(media): rework portrait image sizing to fill+object-contain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Chasing this through width/height class combinations (w-fit/h-fit vs w-auto/h-auto) kept trading one bug for another: centering broke height, fixing height broke centering. Root cause: max-h-full/max-w-full on the image are percentages, and every wrapper in the chain only ever had an intrinsic (auto/fit-content) size — CSS treats percentages against an intrinsically-sized parent as unresolvable, so which axis "won" depended on incidental flex-stretch behavior rather than anything deliberate. Replaced the shrink-wrap-to-image approach with fill-the-definite-parent: wrapper and image now take w-full h-full of the already definitely-sized media column (PostDetailDialog) / full-screen overlay (StoryViewer), and object-contain (default centered) handles aspect-ratio scaling entirely on its own — no percentage resolution against an ambiguous parent left anywhere in the chain. Not visually verified locally (auth-gated route) — needs a real check against a portrait post/story after deploy. --- src/components/feed/PostDetailDialog.tsx | 20 ++++++++++++++------ src/components/stories/StoryViewer.tsx | 21 ++++++++++++--------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/components/feed/PostDetailDialog.tsx b/src/components/feed/PostDetailDialog.tsx index 9b108c2..6b387be 100644 --- a/src/components/feed/PostDetailDialog.tsx +++ b/src/components/feed/PostDetailDialog.tsx @@ -243,6 +243,14 @@ export function PostDetailDialog({ post, open, onClose, onDeleted }: PostDetailD ); + // Image wrappers below fill the (definitely-sized) media column and let + // object-contain handle aspect-ratio scaling/centering. An earlier + // "shrink-wrap to the image's own rendered box" approach relied on + // percentage max-height/max-width resolving against an intrinsically-sized + // (auto/fit-content) parent, which CSS treats as unresolvable — portrait + // images ended up either uncentered or rendered at full natural size + // (clipped) depending on which axis lost. Filling a definite-size parent + // avoids that class of bug entirely. const mediaContent = post.type === "VIDEO" && post.videoPost ? (
{images.map((img) => ( - + ))} @@ -288,13 +296,13 @@ export function PostDetailDialog({ post, open, onClose, onDeleted }: PostDetailD
) : ( -
+
diff --git a/src/components/stories/StoryViewer.tsx b/src/components/stories/StoryViewer.tsx index 7909ed9..be61f2c 100644 --- a/src/components/stories/StoryViewer.tsx +++ b/src/components/stories/StoryViewer.tsx @@ -155,20 +155,23 @@ export function StoryViewer({ ))}
- {/* Story image — inline-flex wrapper shrinks to the actual rendered - image box (not the full-screen overlay) so both the centering - and the badge overlay track the real image bounds. BlurImage's - own wrapper defaults to w-full/h-full (fine for fill-container - usages like feed thumbnails), so it's overridden here via - wrapperClassName. */} + {/* Story image — wrapper fills the full-screen overlay and + object-contain does all the aspect-ratio scaling/centering + itself. A previous "shrink-wrap to the image's own rendered + box" approach relied on percentage max-height/max-width + resolving against an intrinsically-sized (auto/fit-content) + parent, which CSS treats as unresolvable — portrait images + would render at full natural size (clipped) or lose centering + depending on which axis' ambiguity won. Filling a definite-size + parent sidesteps that class of bug entirely. */} {mediaUrl && ( -
+