fix(website): keep plugin carousels from widening the mobile page (#6367)

Anchor the absolutely positioned screen reader install label to its count. Without a containing block inside the carousel, the invisible label escapes the scroll container and expands the document.
This commit is contained in:
Mohamed Boudra
2026-10-08 11:15:14 +01:00
committed by GitHub
parent 99fc204c55
commit 23d7a089e2
2 changed files with 36 additions and 1 deletions
+35
View File
@@ -15,6 +15,41 @@ function pluginCards(page: Page, section: string): Locator {
.filter({ hasNotText: /^See all$/ });
}
test("scrolls mobile plugin carousels without widening the page", async ({ page }) => {
await page.setViewportSize({ width: 390, height: 844 });
await openPlugins(page);
await expectPageWithinViewport(page);
await scrollPluginCarousel(page, "Featured");
await scrollPluginCarousel(page, "What’s new");
await expectPageWithinViewport(page);
});
async function expectPageWithinViewport(page: Page) {
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(
await page.evaluate(() => document.documentElement.clientWidth),
);
await page.evaluate(() => window.scrollTo({ left: 1000, behavior: "instant" }));
expect(await page.evaluate(() => window.scrollX)).toBe(0);
}
async function scrollPluginCarousel(page: Page, section: string) {
const cards = pluginCards(page, section);
// The cards share a non-semantic scrolling container.
const strip = cards.first().locator("..");
await strip.evaluate((element) =>
element.scrollIntoView({ block: "center", behavior: "instant" }),
);
expect(await strip.evaluate((element) => element.scrollWidth)).toBeGreaterThan(
await strip.evaluate((element) => element.clientWidth),
);
await expect(cards.last()).not.toBeInViewport();
await strip.evaluate((element) =>
element.scrollTo({ left: element.scrollWidth, behavior: "instant" }),
);
await expect(cards.last()).toBeInViewport({ ratio: 1 });
await expect(cards.first()).not.toBeInViewport();
}
test("browses from the directory into a category, a plugin, and its author", async ({
page,
context,
@@ -4,7 +4,7 @@ import { formatInstalls } from "./registry";
/** An install count as a download icon and the number; inherits the surrounding text style. */
export function InstallCount({ count }: { count: number }) {
return (
<span className="inline-flex items-center gap-1 tabular-nums">
<span className="relative inline-flex items-center gap-1 tabular-nums">
<Download aria-hidden className="h-3 w-3" />
{formatInstalls(count)}
<span className="sr-only">installs</span>