Skip to content

🐛 Fix homepage hero scroll arrow landing position - #4967

Closed
designbyalex wants to merge 2 commits into
mainfrom
fix/4928-hero-scroll-arrow
Closed

🐛 Fix homepage hero scroll arrow landing position#4967
designbyalex wants to merge 2 commits into
mainfrom
fix/4928-hero-scroll-arrow

Conversation

@designbyalex

@designbyalex designbyalex commented Aug 6, 2026

Copy link
Copy Markdown
Member

The scroll arrow aimed at itself — it scrolled so the button sat 10% of the viewport height from the top, which isn't where the next section starts. A slice of hero stayed on screen, and because the offset was a fraction of viewport height, the landing spot drifted with screen size.

Now it aims at the next block: skips its wrapper padding and scrolls to its first content element.

Viewport Old New Short by
1440×900 633px 894px 261px
390×844 465px 720px 255px

Also moves focus to the landed section for screen readers, and respects prefers-reduced-motion ("instant" not "auto"auto defers to the global scroll-smooth CSS), plus a one-line comment fix in v2ComponentWrapper.tsx: scroll-mt-24 isn't a sticky-header offset, the header isn't sticky.

Verified in Chrome, desktop and mobile. No automated test — jsdom has no layout engine, so Jest can't assert scroll positions.

  • Include Done Video or screenshots – see below

Desktop Before

desktop-before

Desktop After

desktop-after

Mobile Before

mobile-before

Mobile After

mobile-after

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings August 6, 2026 01:22
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Coverage report

St.
Category Percentage Covered / Total
🔴 Statements 0.67% 320/47707
🔴 Branches 9.77% 52/532
🔴 Functions 1.25% 6/481
🔴 Lines 0.67% 320/47707

Test suite run success

19 tests passing in 2 suites.

Report generated by 🧪jest coverage report action from fe2c772

This comment was marked as outdated.

@designbyalex designbyalex self-assigned this Aug 6, 2026
The scroll arrow aimed at itself: it scrolled so the button sat 10% of the
viewport height from the top of the screen. That is a proxy for, not the same
as, the start of the next section, so a slice of hero stayed on screen and the
next section was pushed down and cut off. Because the offset was a fraction of
viewport height, the landing spot also drifted with screen size.

It now aims at the next block. V2ComponentWrapper marks its inner content
section with data-block-content, so the target is declared rather than guessed
at by walking the DOM: decorative layers (bleed image, redGlow, gridOverlay)
render outside that marker and can no longer be mistaken for content, and
wrapper padding is skipped by reading the content container directly.

findNextBlock steps over blocks that render nothing, are hidden at the current
breakpoint, or are decorative. Spacer now carries aria-hidden on whichever
element it renders outermost — previously only its undecorated branch had it,
so a decorated spacer or one with hideOn set could become the scroll target.

Also honours prefers-reduced-motion ("instant" rather than "auto", since auto
defers to the global scroll-smooth in styles.css), and moves focus to the
landed section so screen readers and the keyboard follow the viewport.

Verified in Chrome at 1440x900 and 390x844: the next block's content lands at
the top of the viewport, where the old code stopped 261px and 255px short.

Fixed #4928

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@designbyalex
designbyalex force-pushed the fix/4928-hero-scroll-arrow branch from b011420 to 6e785d6 Compare August 6, 2026 03:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Suppressed comments (1)

lib/scrollToBlock.ts:47

  • ScrollToOptions.behavior only standardizes "auto" and "smooth"; "instant" is non-standard and may be ignored on some browsers, which would make the reduced-motion path still animate due to the global scroll-smooth CSS. To reliably honor prefers-reduced-motion, force scroll-behavior: auto on the root element for the duration of the scroll and use behavior: "auto".
  window.scrollTo({
    top: getBlockContentTop(blockRoot),
    // "instant" not "auto" — auto defers to the global scroll-smooth CSS.
    behavior: prefersReducedMotion() ? "instant" : "smooth",
  });

@designbyalex

Copy link
Copy Markdown
Member Author

Closed and superseded by #4969

designbyalex added a commit that referenced this pull request Aug 6, 2026
The arrow landed 10% of viewport height *below* the top of the screen,
leaving a slice of hero on view. Negating the offset lands it 10%
*above* instead, so the hero clears the viewport.

```diff
- top: window.scrollY + top - window.innerHeight * 0.1,
+ top: window.scrollY + top + window.innerHeight * 0.1,
```

- Affected routes: `/`
- Closes #4928

> [!NOTE]
> Overlaps with #4967, which rewrites the same handler. Merge one, not
both.

## Testing

Chrome DevTools, homepage, checking the service cards section is fully
in view after the scroll settles:

| Viewport | Result |
|---|---|
| 768 × 1024, 1440 × 900, 1920 × 1080 | ✅ |
| 390 × 844, 1280 × 800, 1366 × 768 | ⚠️ cards clipped 64–110 px |
| 375 × 667 | ❌ cards clipped 326 px |

Heading is always visible. Remaining clipping is because the formula
aims at the button, not the section — and at 375 × 667 and 1366 × 768
the content is taller than the viewport, so no scroll offset fits it.
Those need `py-24` or the card graphic shrunk.

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐛 Bug - Homepage scroll arrow does not align to next section

2 participants