fix(embeds): players fill the card and keep their aspect ratio (#228)
Two sizing bugs, both visible the moment a video starts: 1. The video/TikTok embed columns had no width. UrlPreview is a flex ROW, so they shrink-to-fit: the facade's <img> supplied the width, but the player <iframe> is absolutely positioned and supplies none, so pressing play collapsed the whole embed to the iframe's ~200px intrinsic size (measured 606x341 -> 204x115 in a 608px card). Both columns are now width: 100%. 2. EmbedMediaPortrait's 9:16 came from a 177.78% padding-top, but a padding percentage resolves against the CONTAINING BLOCK's width, not the element's — so inside a wide card a Short/TikTok rendered 300x1077 instead of 300x533. Capped with min() so it is exact at >= 300px and still correct on narrower phones. Audited every provider before/after play at 1300 px, 500 px and Pixel 7: YouTube, Vimeo, Twitch 16:9 (0.56); Shorts, TikTok 9:16 (1.78); Spotify 152 px and SoundCloud 166 px fixed-height — all stable across play. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
@@ -246,11 +246,15 @@ export const EmbedMediaPortrait = style([
|
||||
DefaultReset,
|
||||
{
|
||||
position: 'relative',
|
||||
width: toRem(300),
|
||||
maxWidth: '100%',
|
||||
// 9:16 via the padding-top hack (177.78%) — see EmbedMediaLandscape.
|
||||
// [Gitea #228] `min()` on both axes so the 9:16 ratio holds whatever the
|
||||
// parent's width is. A padding-top percentage resolves against the
|
||||
// CONTAINING BLOCK's width, not the element's, so a bare `177.78%` inside a
|
||||
// wide card made the box ~2x too tall (606px card → 1077px instead of 533).
|
||||
// Capped at the pixel height of a 300px-wide 9:16 box, it is exact when the
|
||||
// parent is at least 300px and falls back to the percentage below that.
|
||||
width: `min(${toRem(300)}, 100%)`,
|
||||
height: 0,
|
||||
paddingTop: '177.78%',
|
||||
paddingTop: `min(${toRem(533)}, 177.78%)`,
|
||||
margin: '0 auto',
|
||||
overflow: 'hidden',
|
||||
backgroundColor: color.Surface.Container,
|
||||
|
||||
@@ -1203,7 +1203,11 @@ function MediaEmbedCard({
|
||||
};
|
||||
|
||||
return (
|
||||
<Box direction="Column">
|
||||
// [Gitea #228] `width: 100%` — UrlPreview is a flex ROW, so this column
|
||||
// shrink-to-fits its content. The facade's <img> supplied that width, but
|
||||
// the player <iframe> is absolutely positioned and contributes none, so on
|
||||
// play the whole embed collapsed to the iframe's ~200px intrinsic size.
|
||||
<Box direction="Column" style={{ width: '100%', minWidth: 0 }}>
|
||||
{playing && rich ? (
|
||||
// Rich post embeds (Instagram/Reddit) are variable-height and self-size.
|
||||
<iframe
|
||||
@@ -1380,7 +1384,9 @@ function TikTokEmbedCard({ url, prev }: { url: string; prev: IPreviewUrlResponse
|
||||
);
|
||||
|
||||
return (
|
||||
<Box direction="Column">
|
||||
// [Gitea #228] See the video embed above: this column must fill the card's
|
||||
// flex row, not shrink to the iframe's intrinsic width.
|
||||
<Box direction="Column" style={{ width: '100%', minWidth: 0 }}>
|
||||
<div ref={mediaRef} className={previewCss.EmbedMediaPortrait}>
|
||||
{playing && videoId ? (
|
||||
<iframe
|
||||
|
||||
Reference in New Issue
Block a user