From 18c2ed0bfebcbebc6d6b79082dadc57679ada85e Mon Sep 17 00:00:00 2001 From: Claude Opus 5 Date: Sat, 1 Aug 2026 07:37:05 +0200 Subject: [PATCH] #301: the real culprit was the jump nav, not the wide content MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first attempt fixed plausible suspects. CI measured the actual page and named something else: six `.settings-nav__link` buttons, 417px of page-level overflow at 320px. `.settings-nav` already had `overflow-x: auto`, but as a flex child it also had the default `min-width: auto` — the min-content width of the whole jump strip. That forced the column wider than the viewport, so its own overflow rule never had anything to scroll. `min-width: 0` is exactly the case CLAUDE.md warns about under Reflow. The guard now ignores elements that sit inside a scroll container. Such content is *meant* to be wider than the viewport — reporting it buried the one finding that mattered under twelve lines of noise, and the cap truncated the list before it could show anything else. The table wrapper and the wrapping settings rows from the first commit stay. Neither was the cause here, but a table cannot shrink below its min-content width and those rows cannot wrap on their own, so both are hardening that holds regardless of content. --- apps/web/e2e/a11y.spec.ts | 15 +++++++++++++-- apps/web/src/styles/base.css | 6 ++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/web/e2e/a11y.spec.ts b/apps/web/e2e/a11y.spec.ts index 92626bb..2d323ab 100644 --- a/apps/web/e2e/a11y.spec.ts +++ b/apps/web/e2e/a11y.spec.ts @@ -120,11 +120,22 @@ async function expectNoHorizontalScroll(page: Page, label: string): Promise { const doc = document.documentElement; const limit = doc.clientWidth; + /** Content inside its own scroll container is allowed to be wider than + * the viewport — that is the prescribed remedy, not the defect. Only + * what pushes the PAGE is a finding. */ + const insideScroller = (el: HTMLElement): boolean => { + for (let node = el.parentElement; node && node !== doc; node = node.parentElement) { + const overflowX = getComputedStyle(node).overflowX; + if (overflowX === 'auto' || overflowX === 'scroll' || overflowX === 'hidden') return true; + } + return false; + }; + const offenders: string[] = []; for (const el of Array.from(document.querySelectorAll('body *'))) { const rect = el.getBoundingClientRect(); // 1 px Toleranz gegen Subpixel-Rundung. - if (rect.width > 0 && rect.right > limit + 1) { + if (rect.width > 0 && rect.right > limit + 1 && !insideScroller(el)) { const cls = el.className && typeof el.className === 'string' ? `.${el.className.trim().split(/\s+/).join('.')}` @@ -134,7 +145,7 @@ async function expectNoHorizontalScroll(page: Page, label: string): Promise