Fill the preview's width in Safari

- A ratio with a height cap let Safari keep the ratio by narrowing the box:
  once a long device name widened the menu past 313px, the preview stopped
  short and left a strip of menu at its right. Chromium stretched it.
- A fixed height instead, cropped by the picture: sixteen by nine at the
  menu's narrowest, wider as the menu widens, the same in both engines.
  Measured in WebKit before and after, 313px against a 398px menu, then
  398px.
- Guarded in a wide menu, though in Chromium only: no test tier here runs
  WebKit, so the story holds the requirement rather than the engine.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
fkwp
2026-09-23 09:58:42 +02:00
co-authored by Claude Opus 5.5
parent 45469f3828
commit 31f057726f
3 changed files with 42 additions and 10 deletions
@@ -436,9 +436,12 @@ Please see LICENSE in the repository root for full details.
* frame's corner, because a video paints on a layer of its own and would
* otherwise draw over the outline the menu is framed with.
*
* Sixteen by nine and never taller than its budget, cropped rather than
* letterboxed: a face cut at the edge reads as a self-view, a face in bars
* reads as a broken one.
* A fixed height rather than a ratio: sixteen by nine at the menu's narrowest,
* and wider as a long device name widens the menu, cropped rather than
* letterboxed — a face cut at the edge reads as a self-view, a face in bars
* reads as a broken one. Not aspect-ratio with a height cap: once the cap
* holds, Safari keeps the ratio by narrowing the box instead of the picture,
* and the preview stops short of the menu's right edge.
*/
.selfPreview {
position: relative;
@@ -450,8 +453,7 @@ Please see LICENSE in the repository root for full details.
);
margin-inline: var(--cpd-border-width-1);
margin-block-end: var(--cpd-space-2x);
aspect-ratio: 16 / 9;
max-block-size: 176px;
block-size: 176px;
overflow: hidden;
border-start-start-radius: calc(
var(--cpd-space-3x) - var(--cpd-border-width-1)
@@ -1168,6 +1168,36 @@ export const BackgroundEffectsWithALongDeviceName: Story = {
},
};
/**
* A long device name widens the menu past the width at which the preview is
* sixteen by nine. The preview still spans it: Safari, given a ratio and a
* height cap, kept the ratio by narrowing the box and left a strip of menu at
* its right. Checked here in Chromium, which never did — no test tier here
* runs WebKit — so this holds the requirement, not the engine.
*/
export const BackgroundEffectsWithPreviewInAWideMenu: Story = {
args: {
...BackgroundEffectsWithALongDeviceName.args,
selfPreview: <img src={cameraStandIn} alt="" />,
},
parameters: { callAreaHeight: 720 },
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await userEvent.click(canvas.getByRole("button", { name: "Camera" }));
await within(document.body).findByRole("menuitemradio", { name: "Blur" });
const menu = document.body.querySelector("[role='menu']")!;
const preview = menu.querySelector<HTMLElement>(`.${styles.selfPreview}`)!;
const frame = menu.getBoundingClientRect();
const box = preview.getBoundingClientRect();
// Wider than the preview's sixteen-by-nine width, or this proves nothing.
await expect(frame.width).toBeGreaterThan((176 * 16) / 9 + 8);
await expect(frame.right - box.right).toBeLessThanOrEqual(2);
await expect(box.left - frame.left).toBeLessThanOrEqual(2);
await expect(Math.round(box.height)).toBe(176);
},
};
/**
* Backgrounds the user added are theirs to remove — except the one in force,
* which is what they are wearing.
+5 -5
View File
@@ -188,11 +188,11 @@ const MIN_LIST_HEIGHT = 160;
/**
* The most the self-preview may take, which is also what it costs the list.
*
* Drawn at sixteen by nine across the full width of the menu, capped here so
* that a menu widened by a long device name cannot make it taller than its
* budget. The preview is paid for out of the list's share rather than on top
* of it, so the menu is never taller for having one: where the list could not
* keep its floor after paying, there is no preview at all.
* Its fixed height: sixteen by nine across the menu at its narrowest, and
* cropped wider as the menu widens, so it never costs more than this. The
* preview is paid for out of the list's share rather than on top of it, so the
* menu is never taller for having one: where the list could not keep its floor
* after paying, there is no preview at all.
*/
const PREVIEW_BLOCK = 176;