diff --git a/src/index.css b/src/index.css index 3a35d24..6481b83 100644 --- a/src/index.css +++ b/src/index.css @@ -110,6 +110,12 @@ } } +@media (prefers-reduced-motion: reduce) { + .content-balloon { + animation: none !important; + } +} + @keyframes vibe-shimmer { 0% { background-position: 0% 50%; diff --git a/tests/e2e/content-balloon-layout.spec.ts b/tests/e2e/content-balloon-layout.spec.ts index 4e72f24..f6a62c8 100644 --- a/tests/e2e/content-balloon-layout.spec.ts +++ b/tests/e2e/content-balloon-layout.spec.ts @@ -88,6 +88,17 @@ async function expectNoHorizontalOverflow(page: Page) { expect(geometry.scroll).toBeLessThanOrEqual(geometry.client + 1) } +test('content balloons honor reduced-motion preferences', async ({ page }) => { + await page.emulateMedia({ reducedMotion: 'reduce' }) + await page.setViewportSize({ width: 390, height: 844 }) + await loadWithFacts(page, PRODUCT_PATH) + const animationNames = await page.locator('[data-content-balloon]').evaluateAll((nodes) => + nodes.map((node) => getComputedStyle(node).animationName), + ) + expect(animationNames.length).toBeGreaterThan(0) + expect(animationNames.every((name) => name === 'none')).toBe(true) +}) + for (const width of WIDTHS) { test(`PDP smart placements are safe at ${width}px`, async ({ page }) => { await page.setViewportSize({ width, height: 900 })