From 0420f97c42361cb1bbb79e04d406dda6170c057c Mon Sep 17 00:00:00 2001 From: Claude Opus 5 Date: Sat, 1 Aug 2026 11:15:36 +0200 Subject: [PATCH] #301: sort the reflow report so the culprit cannot be buried MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI still reports 737 while the local stack is now clean, and the box list was capped at 15 entries — all of them nav links clipped by their own scroller. Whatever pushes the page in CI sits past that cap. The list is now sorted by reach, marks each entry as either clipped by a fitting scroller or actually pushing the page, and shows 40. --- apps/web/e2e/a11y.spec.ts | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/apps/web/e2e/a11y.spec.ts b/apps/web/e2e/a11y.spec.ts index 3e3223d..e51f718 100644 --- a/apps/web/e2e/a11y.spec.ts +++ b/apps/web/e2e/a11y.spec.ts @@ -141,20 +141,36 @@ async function expectNoHorizontalScroll(page: Page, label: string): Promise 0 && rect.right > limit + 1) { - past.push(`${describe(el)} right=${Math.round(rect.right)} w=${Math.round(rect.width)}`); + /** Content inside a scroll container may exceed the viewport — that is + * the remedy. But only when the CONTAINER fits: a scroller that is + * itself too wide still pushes the page. */ + const insideFittingScroller = (el: Element): boolean => { + for (let node = el.parentElement; node && node !== doc; node = node.parentElement) { + const ox = getComputedStyle(node).overflowX; + if (ox === 'auto' || ox === 'scroll' || ox === 'hidden') { + return node.getBoundingClientRect().right <= limit + 1; + } } - } + return false; + }; + + // Widest reach first, so a long tail of clipped children cannot bury the + // one box that actually pushes the page. + const past = Array.from(document.querySelectorAll('body *')) + .map((el) => ({ el, rect: el.getBoundingClientRect() })) + .filter(({ rect }) => rect.width > 0 && rect.right > limit + 1) + .sort((a, b) => b.rect.right - a.rect.right) + .map( + ({ el, rect }) => + `${describe(el)} right=${Math.round(rect.right)} w=${Math.round(rect.width)}` + + `${insideFittingScroller(el) ? ' [in fitting scroller]' : ' <-- pushes page'}`, + ); return { overflowBy: doc.scrollWidth - limit, viewport: `html client=${limit} scroll=${doc.scrollWidth} | body client=${document.body.clientWidth} scroll=${document.body.scrollWidth} rect=${Math.round(document.body.getBoundingClientRect().width)}`, overflowing: overflowing.slice(0, 15), - past: past.slice(0, 15), + past: past.slice(0, 40), }; }); const diagnosis = [