Skip to content

fix(docsite): pin the hero with sticky rails, drop the overscroll suppression - #5480

Draft
AKnassa wants to merge 1 commit into
facebook:mainfrom
AKnassa:rocky/issue-5470-hero-sticky-rails
Draft

fix(docsite): pin the hero with sticky rails, drop the overscroll suppression#5480
AKnassa wants to merge 1 commit into
facebook:mainfrom
AKnassa:rocky/issue-5470-hero-sticky-rails

Conversation

@AKnassa

@AKnassa AKnassa commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Step 2 of #5392. Fixes #5470.

What this does

Keeps the home page hero pinned exactly as it is today, but without the CSS rule that switched off the browser's native overscroll. On a Mac trackpad the page rubber-bands again at the top and bottom, like every other page on the web. Nothing changes visually.

Why

The hero's three pinned layers (the aurora glow, the floating cards and the headline block) were position: fixed. A fixed layer is glued to the screen rather than to the page, so when the page rubber-bands past its own end the layer sits in the gap that opens up. #3032 hid that by turning overscroll off for the whole site, and #5415 narrowed the rule to desktop widths to give mobile its pull-to-refresh back. This finishes the job: the layers are now position: sticky inside full-height rails, so they lift with the page and physically cannot paint past its end. That is structural, which is why the rule can be deleted instead of narrowed further.

What changed

  • Each pinned layer rides its own rail: a position: absolute; inset: 0 box that is a direct child of heroScope, spans the hero band and the showcase, and sits ahead of the showcase overlay so tree order still equals paint order (backdrop, cards, hero text, then the showcase covering them). A rail inside the 760px band alone releases its layer after about 48px, which is the trap the issue calls out.
  • backdropGlow, the cards stage and heroContent go fixed -> sticky; top: var(--appshell-header-height) at 1024px and up. Narrow widths are untouched: the glow stays absolute and the hero text stays in flow.
  • Centering moves from left: 50% + translateX(-50%) to auto margins in the full-width rail (on a sticky box left is an inset, not an offset). The 1200px box is capped to the rail's width rather than 100vw: with a classic scrollbar 100vw is wider than the rail, which zeroes the auto margins and shoves the box left.
  • HeroReelProvider renders no DOM any more. Its hover / focus / touch surface is the new HeroReelSwipeArea, which page.tsx uses as the hero text's rail, so the band and its gutters still pause the reel and the phone collage still swipes. HeroReelCards is split into HeroReelBackdrop (fills + glow) and HeroReelCards (stage).
  • The @media (min-width: 1024px) { html { overscroll-behavior-y: none } } block is deleted from globals.css.
  • A comment on LayoutContent's overflow: clip records why it must stay clip: hidden or auto there would silently un-pin the landing page (the issue asked for this).
  • New home-hero-overscroll.test.ts. The docsite suite is node-only with StyleX untransformed, so these are source invariants in the shape of component-preview-theme.test.ts: globals.css never suppresses overscroll at any width; none of the three layers is ever fixed in any media arm; the rails are bounded by heroScope and precede the showcase; the boxes are sized against the rail, not 100vw; and the AppShell / LayoutContent links that keep the main area a non-scroll container (overflow: clip, isScrollable={isFill}, the landing layout's height="auto") hold. It is red on main today, and 11 single-line mutations (a fixed behind a trailing comment, double quotes, a computed [BREAKPOINT] key, an overflowY longhand, isScrollable unconditional, height="fill", the width back to 100vw, heroScope static, a rail moved after the showcase, overscroll-behavior: contain, an uppercase rule) each turn it red again.

How to see it

Nothing should look different; that is the point. Run the docsite with the canary banner off so the header is the production 48px (NEXT_PUBLIC_DOCS_TARGET=latest pnpm -F @astryxdesign/docsite dev), open the home page on a Mac and rubber-band at the bottom: the page bounces and the footer stays clean. The Vercel preview on this PR shows the same page.

Measured against an untouched main checkout with Playwright + pixelmatch, both served with the banner hidden, prefers-reduced-motion: reduce so the reel holds its first slide, and transitions frozen, at ten scroll offsets per viewport (0, 100, 200, 400, 712, 760, 800, 1400, 2200, max):

viewport pixels differing from main overscroll-behavior-y fixed layers reaching the viewport bottom at page end
1280 x 900 0 none -> auto 2 -> 0
1280 x 600 0 none -> auto 3 -> 0
1440 x 1400 0 none -> auto 0 -> 0
1024 x 768 0 none -> auto 2 -> 0
900 x 1200 0 auto -> auto 0 -> 0
390 x 844 0 auto -> auto 0 -> 0

Layer geometry matches fixed at every offset (hero text at y=48 and 712px tall, glow and stage at x=40 and 1200px wide at 1280) until max scroll, where sticky releases behind the opaque showcase. Document height is unchanged (3540px). elementFromPoint on the "Get started" button still returns the button.

Also checked on both trees: hover in the gutter, on the CTA and over the pinned hero while scrolled pauses the reel, hover on the showcase does not, keyboard focus on a dot pauses and blur resumes, a phone swipe steps the reel left and right and a vertical drag does not (11 checks, identical results before and after); resize while scrolled (1280 -> 1440 -> 1100 at scroll 400) and a theme swap mid-scroll with transitions running, 0 pixels differing; and a forced 15px classic scrollbar, where the old fixed box sat at x=-7.5 overflowing both sides and the new one sits centered inside the rail.

pnpm -F @astryxdesign/docsite test (27 files, 413 tests), tsc --noEmit, strict eslint and pnpm lint:strict (0 errors) are green.

Not verified here

Safari and WebKit, and a real rubber-band gesture, which cannot be driven headlessly. That is the careful visual pass the issue budgets for.

Related

Contain the desktop-pinned hero layers so the app-global
`overscroll-behavior-y: none` can be deleted outright instead of gated
to desktop widths: macOS trackpads get their native rubber-band back.

A `fixed` layer is not part of the document, so when the document
rubber-bands past its own edge the layer sits in the exposed gap. A
`sticky` layer lifts with the document and cannot paint past its
containing block. Each pinned layer (aurora backdrop, overlap cards,
hero text) now rides its own `absolute; inset: 0` rail, a direct child
of heroScope spanning hero band + showcase and placed ahead of the
showcase overlay, as a `position: sticky` box at >=1024px. Centering
moves from `left: 50%` + `translateX(-50%)` to auto margins inside the
full-width rail, and the 1200px box is capped to the rail's width rather
than 100vw: with a classic scrollbar 100vw is wider than the rail, which
zeroes the auto margins and shoves the box left. A rail inside the 760px
band alone would release the layer after ~48px, which is why the rails
span the showcase too.

HeroReelProvider is context-only now; its hover/focus/touch surface is
the new HeroReelSwipeArea, which page.tsx uses as the hero text's rail
so the band still pauses the reel and the mobile collage still swipes.

Also records on LayoutContent why `overflow: clip` must stay `clip`:
`hidden` or `auto` there would silently un-pin the landing page. A
source-invariant test (the docsite suite is node-only) guards the rule's
absence, the three layers never going back to `fixed`, the rails' order
and containment, and the AppShell/LayoutContent links that keep the main
area a non-scroll container.

Verified against untouched main with Playwright + pixelmatch at six
viewports x ten scroll offsets: 0 px at the default threshold, identical
layer geometry, `overscroll-behavior-y: auto` everywhere, no fixed
element reaching the viewport bottom (was 2-3), 11/11 hover/focus/swipe
checks passing on both trees, resize-while-scrolled and theme-swap
mid-scroll 0 px. Safari and a real rubber-band are not verified here.

Step 2 of facebook#5392. Fixes facebook#5470. Supersedes the zero-height-pin approach
in facebook#5431 and folds in the backdropGlow comment correction from facebook#5467.
@vercel

vercel Bot commented Aug 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
astryx Error Error Aug 25, 2026 4:51am

Request Review

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Aug 25, 2026
@github-actions github-actions Bot added community Authored by a community contributor (not on the eng/design team) needs:code-review High-risk change (new package/component/API) — needs human code review before merge needs:design-review Affects visuals — Design should review labels Aug 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

🧪 Sandbox Preview

View Sandbox for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

Modified Components

Layout (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 1481 -
Complexity N/A Very High (84) -

Bundle Size Summary

Package Size (ESM) Size (CJS) Gzipped
@astryxdesign/core N/A 4.8KB 1.2KB

Accessibility Audit

Status: 1 accessibility violation(s) found — 1 serious.

Layout - 1 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 1/18 stories · Learn more
    • WCAG: 1.4.3 (Level AA)

Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot. community Authored by a community contributor (not on the eng/design team) needs:code-review High-risk change (new package/component/API) — needs human code review before merge needs:design-review Affects visuals — Design should review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docsite: contain the desktop-pinned hero layers so overscroll suppression can be removed entirely

1 participant