flarum / flarum/framework

PostStream requests the next page too late, so arriving posts shove the footer off screen (CLS ~0.9 on mobile)

Open Beginner friendly
#5,007 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
PHP
Stars
6.7k
Forks
883
Avg merge
15h 16m
Merged PRs (30d)
73

Description

### Current Behavior

`PostStream#loadPostsIfNeeded()` only requests the next page of posts once the end of the loaded stream comes within a fixed **300 px** of the viewport bottom:

https://github.com/flarum/framework/blob/2.x/framework/core/js/src/forum/components/PostStream.js#L227-L241

```js
const loadAheadDistance = 300;
...
if ($item.length && $item.offset().top + $item.outerHeight(true) < viewportTop + viewportHeight + loadAheadDistance) {
this.stream.loadNext();
}
```

On a phone, on a real connection, that request is still in flight when the page footer scrolls into view. The posts then arrive and shove the footer out of the viewport — one layout shift of **~0.9**, which on its own rates the whole page view "poor" for CLS.

It reproduces for guests and members alike, on every discussion with more than one page of posts, so it affects a large share of mobile discussion views on any forum.

Captured from the shift entry (mobile viewport 412x823):

```
v=0.8967 DIV.custom-footer prev y=743 h=79 -> cur y=0 h=0
PostStream items 20 -> 40, stream height 11366 -> 18937
```

Desktop is essentially unaffected (measured 0.003 on the same thread) because the same footer movement is a much smaller fraction of a large viewport — which is why this tends to show up only in the mobile half of Search Console's Core Web Vitals report.

### Steps to Reproduce

1. Open a discussion with more than 20 posts on a phone-sized viewport (412x823), on a throttled connection (~1.6 Mbps, 150 ms latency).
2. Scroll to the bottom of the first page of posts so the footer comes into view.
3. Watch the footer as the next page arrives — it is pushed off screen.

Measured with a buffered `PerformanceObserver` on `layout-shift` (`hadRecentInput` entries excluded), scrolling with real wheel input via CDP `Input.dispatchMouseEvent`, headless Chrome 140, 4x CPU throttle.

### Expected Behavior

The next page should be requested early enough that it arrives while the end of the stream is still below the fold, so the growth happens off screen and costs no layout shift. The same pages are fetched either way — only the timing changes.

Scaling the look-ahead with the viewport instead of using a fixed 300 px is enough:

```js
const loadAheadDistance = Math.max(300, $(window).height() * 1.5);
```

**Measured on an 85-post discussion read to the bottom: CLS 0.897 -> 0.018.**

I have this running in production as an extension override and am happy to open a PR with a regression test if the approach looks right.

### Environment

- Flarum version: 2.0.0-rc.8
- Website URL: https://pianoclack.com
- Webserver: nginx
- Hosting environment: VPS
- PHP version: 8.4.24
- Browser: Chrome 140 (mobile emulation, and reproduced on real Android Chrome field data)

Contributor guide

Open the contributing guide

Research direction

Start in framework/core/js/src/forum/components/PostStream.js at lines 227-241 and inspect PostStream#loadPostsIfNeeded(). Reproduce the mobile scenario at 412x823 on a throttled connection, then verify that the next page is requested earlier and that posts arrive without pushing the footer into view; the issue also calls for a regression test.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
frontend, performance
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.