Keep a post inside the window, and stop letterboxing it
CI / Typecheck, test, build (pull_request) Successful in 34s

On a desktop a portrait video came with black bars all the way around and sat
partly below the fold, so you had to scroll to find the thing you had opened.

The bars were the figure, not the video. It carried the media's aspect ratio,
so at the full width of the column a 720x1280 reel forced a box 1204px tall
inside a 982px window, and the video -- capped at 78vh -- floated in the middle
of it with 438px of black above and below and 247px either side. The ratio now
goes on the media itself, which sizes to its own proportions instead of being
stretched to the column, and the background is the card's rather than black, so
what space is left reads as page instead of as a border.

The height cap is the window less the chrome around it. Deriving that from the
layout is the obvious approach and does not work: the card is sized by its
contents, so every percentage height inside resolves to auto and clamps
nothing. Measured across the posts this serves, the header, caption and footer
come to 270-350px, so the cap subtracts 350 and the whole post fits. Smaller
than it might be on a short window, but a video can be full-screened and a post
you have to hunt for cannot.

Threads keep the looser cap and scroll, which a column of several posts was
always going to do.

Grid thumbnails were quietly broken and the measuring turned it up: the cell
takes its height from an aspect ratio, which a percentage height will not
resolve against, and `aspect-ratio: auto` asks for the image's own ratio rather
than none, so a portrait thumbnail rendered at twice the height of its cell and
spilled out. They fill their cell absolutely now.

Verified at 1512x982, 1280x800, 1440x700 and 390x844: no letterboxing anywhere,
and the media sits above the fold on every one.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01BGkRmLfiWuJHx6tQ12EELY
This commit is contained in:
2026-08-26 17:24:22 -03:00
co-authored by Claude Opus 5
parent 60a9468875
commit df50fa7e93
2 changed files with 73 additions and 8 deletions
+64 -6
View File
@@ -86,7 +86,9 @@ main { max-width: 680px; margin: 0 auto; }
/* ---------- media ---------- */
.media { border-block: 1px solid var(--line); background: #000; }
/* Card-coloured, not black: whatever space the media does not fill should
read as part of the page rather than as a border around it. */
.media { border-block: 1px solid var(--line); background: var(--card); }
.post__head + .media, .text + .media { border-top: 1px solid var(--line); }
.media__bar {
@@ -135,14 +137,21 @@ main { max-width: 680px; margin: 0 auto; }
place-items: center;
position: relative;
min-width: 0;
min-height: 0;
}
/* Sized by its own proportions rather than stretched to the column: a
portrait video filling the width is mostly empty space either side of it.
The cap keeps any single item within the window. */
.item img, .item video {
display: block;
width: 100%;
max-height: 78vh;
width: auto;
height: auto;
max-width: 100%;
max-height: 70vh;
max-height: 70dvh;
object-fit: contain;
background: #000;
background: transparent;
}
.item__note {
@@ -162,9 +171,31 @@ main { max-width: 680px; margin: 0 auto; }
overflow: visible;
}
.media[data-view="grid"] .item { aspect-ratio: 1 / 1 !important; cursor: zoom-in; }
.media[data-view="grid"] .item {
aspect-ratio: 1 / 1;
cursor: zoom-in;
overflow: hidden;
}
/*
* Filled absolutely rather than with height: 100%. The cell's height comes
* from its aspect-ratio, which a percentage height will not resolve against,
* and `aspect-ratio: auto` means "use the image's own" rather than "ignore
* ratios" -- between them a portrait thumbnail ends up twice the height of
* its cell.
*/
.media[data-view="grid"] .item img,
.media[data-view="grid"] .item video { height: 100%; max-height: none; object-fit: cover; }
.media[data-view="grid"] .item video {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
max-width: none;
max-height: none;
min-height: 0;
object-fit: cover;
aspect-ratio: auto !important;
}
.media[data-view="grid"] .item__note { display: none; }
/* ---------- footer ---------- */
@@ -272,3 +303,30 @@ main { max-width: 680px; margin: 0 auto; }
without hiding the rest. */
background: color-mix(in srgb, var(--accent, #888) 7%, transparent);
}
/* ---------- fitting the window ---------- */
/*
* On a large screen a single post should be readable without scrolling to
* find it -- a video especially, which you can full-screen if you want it
* bigger.
*
* The cap is the window less the chrome around the media: header, caption and
* footer come to roughly 270-350px on the posts this serves. Deriving it
* instead of subtracting a constant is the obvious thing to try and does not
* work: the card is sized by its contents, so a percentage height inside it
* resolves to auto and clamps nothing.
*
* A thread is a column of several posts and cannot fit whatever we do, so it
* keeps the looser cap above and scrolls.
*/
@media (min-width: 700px) and (min-height: 560px) {
.post:not([data-segments]) .item img,
.post:not([data-segments]) .item video {
max-height: calc(100vh - 350px);
max-height: calc(100dvh - 350px);
/* Below that the media would be too small to be worth showing; better to
let a very long caption scroll. */
min-height: 220px;
}
}