fix(web): clip overflow instead of creating scroll containers
Site CSS clips overflow with overflow: clip instead of overflow: hidden, so clipping boxes are no longer scroll containers. A scroll container captures position: sticky descendants (the cause of the /pear and /reflex sticky-nav bug) and can be scrolled by focus, find-in-page, or scrollIntoView, shifting clipped content.
What the CSS is now
- 136
overflow: hiddendeclarations across 21 CSS modules areoverflow: clip. - 19 declarations stay
hidden, each listed below with its reason. - Boxes that relied on a scroll container's zero automatic minimum size now say so explicitly.
clipkeeps the content-basedmin-width: auto/min-height: autoof flex items, grid items and aspect-ratio boxes:min-width: 0: landing.featurePreview,.searchResults strong,.searchResults span; reflex.assetFrame,.filePath; pear.visual; agents.rowTriggerText; docs.productHeaderTagline; IntegrationGrid.namemin-height: 0: landing.editorCode(column flex item); brand.kitPreview(aspect-ratio box)
- docs
.articleBodyisdisplay: flow-root+overflow: clip. It keeps the block formatting context that stops its first and last children's margins from collapsing through it. - The site has no floats, so no other element depends on the BFC that
hiddencreated.
Layout evidence
Production builds (next build + next start) of the base branch and this branch were fingerprinted with headless Chromium at 1440×900 and 375×812. Each run scrolled through the page to trigger lazy content, paused CSS animations at t=0, and recorded the rounded document-space getBoundingClientRect of every rendered element plus documentElement.scrollWidth/scrollHeight. A second base run filtered out nondeterministic elements.
Pages: /, /docs/introduction, /blog, /blog/introducing-agent-relay, /pear, /reflex, /agents, /agents/cloudflare-monitor, /agents/register, /enterprise, /flows, /file, /primitives (where /schedule, /message, /auth redirect), /brand, /about, /process, /teams, /login, /messaging, /careers, /u/agent-relay, /docs/file/integrations, and a 404 page.
| Viewport | Pages | Elements compared | Geometry diffs | Document size diffs |
|---|---|---|---|---|
| 1440×900 | 26 | 18,771 | 3* | 0 |
| 375×812 | 26 | 18,614 | 2* | 0 |
*All five are paths inside one hero SVG <g> on / and /messaging. That group is animated by script and moves 1–4px between runs; it also differed between the two base runs.
Elements compared per page (desktop / mobile)
| Page | Desktop | Mobile |
|---|---|---|
/ | 3102 | 3101 |
/docs/introduction | 666 | 662 |
/blog | 237 | 237 |
/blog/introducing-agent-relay | 456 | 457 |
/pear | 452 | 451 |
/reflex | 260 | 260 |
/agents | 370 | 368 |
/agents/cloudflare-monitor | 169 | 168 |
/agents/register | 171 | 170 |
/enterprise | 323 | 322 |
/flows | 1295 | 1230 |
/file | 356 | 351 |
/primitives (+ /schedule, /message, /auth) | 253 each | 252 each |
/brand | 301 | 300 |
/about | 1757 | 1756 |
/process | 161 | 160 |
/teams | 3142 | 3077 |
/login | 81 | 81 |
/messaging | 3058 | 3062 |
/careers | 81 | 81 |
/u/agent-relay | 119 | 118 |
/docs/file/integrations | 602 | 598 |
| 404 | 600 | 596 |
The sticky site nav sits at top: 12px (desktop) and 8px (mobile) at mid-page on every page that has it, the same as on base.
npm --workspace web run build and npm --workspace web run test (555 passed, 1 skipped) pass.
Declarations kept as overflow: hidden (19)
Scrolled by script (2)
web/app/landing.module.css.chatStreamoverflow-x/overflow-y:ChannelMessagesPreviewscrolls it withscrollTo/scrollTopto animate the message feed. It must stay a scroll container.
Unreachable modules (16). Nothing renders them, so a change can't be checked:
web/app/schedule/relaycron.module.css(3):/scheduleredirects to/primitives#schedule, andScheduleContentis not imported anywhere.web/app/message/relaycast.module.css(6):/messageredirects to/primitives#message, andRelaycastContentis not imported anywhere.web/app/auth/relayauth.module.css(5):/authredirects to/primitives#auth, andRelayauthContentis not imported anywhere.web/app/flows/onboarding/onboarding.module.css.codePanel,.visuallyHidden(2):/flows/onboardinghas a layout and no page, so it returns 404.
Modal dialog (1)
web/app/flows/onboarding/onboarding.module.css.agentEditor[open]: a<dialog>on the same unreachable route.
web/components/docs/docs-search.module.css is outside this change.
🤖 Generated with Claude Code
[!NOTE]
Low Risk
CSS-only overflow and min-size tweaks with layout fingerprinting showing no document-size regressions; low risk aside from verifying edge-case clipping on affected pages.
Overview
Replaces overflow: hidden with overflow: clip across marketing, docs, and shared component CSS so clipping no longer creates scroll containers. That fixes sticky navigation on pages like /pear and /reflex (ancestors with hidden used to trap position: sticky) and avoids unwanted scrolling from focus, find-in-page, or scrollIntoView inside clipped regions.
Where clip changes minimum sizing behavior, the PR adds explicit min-width: 0 or min-height: 0 on flex/grid children (e.g. ellipsis text, feature previews, kit previews). Docs .articleBody gets display: flow-root plus overflow: clip to preserve margin containment without relying on hidden's BFC.
Intentionally unchanged overflow: hidden remains for script-driven scroll areas (e.g. chat stream) and unreachable or modal-only styles noted in the PR description.
Reviewed by Cursor Bugbot for commit a142048f44af6cf6dc8a709229a3537bb25f0b7d. Bugbot is set up for automated code reviews on this repo. Configure here.
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.
Summary by cubic
Changes the site's CSS to clip overflow with overflow: clip instead of overflow: hidden, so clipping boxes are no longer scroll containers. A scroll container captures position: sticky descendants (the cause of the /pear and /reflex sticky-nav bug) and can be scrolled by focus, find-in-page, or scrollIntoView, shifting clipped content.
Changes
- 136
overflow: hiddendeclarations across 21 CSS modules becomeoverflow: clip; 19 stayhiddenbecause they're scrolled by script, a modal dialog, or in unreachable modules. - Boxes that relied on a scroll container's zero automatic minimum size now set
min-width: 0ormin-height: 0. - docs
.articleBodyusesdisplay: flow-root+overflow: clipto keep the block formatting context that stops child margins from collapsing.
Verification
- Headless Chromium renders of 26 pages at 1440×900 and 375×812 show no layout diffs besides nondeterministic animated SVG paths.
- The sticky nav sits at the same position on every page as on the base branch.
npm --workspace web run testpasses (555 passed, 1 skipped).