Skip to content

Fix scroll timeout by waiting for the scroll position to settle#727

Open
otsch wants to merge 1 commit into
chrome-php:1.15from
otsch:bugfix/scroll-timeout-settle
Open

Fix scroll timeout by waiting for the scroll position to settle#727
otsch wants to merge 1 commit into
chrome-php:1.15from
otsch:bugfix/scroll-timeout-settle

Conversation

@otsch

@otsch otsch commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

The scroll timeout addressed in #678 happens when the page layout changes between the moment Mouse::scroll() computes the target scroll position and the moment it verifies that position. The verify loop waits for the page to reach an exact, pre-computed target. Once the layout shifts mid-scroll, that target can become unreachable and the loop spins until it fails with OperationTimedOut.

While digging deeper into this I (assisted by AI I have to admit ;)) found several distinct ways to reproduce the issue, each added as a test case:

  • scrollShrink.html - the scrollable area shrinks right after the scroll starts.
  • scrollLock.html - an overlay/modal locks scrolling (body becomes position:fixed), so the maximum scroll distance drops to 0.
  • infiniteScroll.html - a lazy-loaded image above the current position finishes loading mid-scroll and shifts the layout (the typical infinite-scroll case).

The fix proposed in #678 (retry once when the recomputed distances changed) only covers the cases where the maximum scroll distance changes: it recovers the shrink and the lock case, but not the layout-shift case. There the page grows, the recomputed distance stays the same, and it still times out - so that fix unfortunately does not solve every variant of the issue.

This change takes a different, more robust approach. Instead of waiting for an exact, pre-computed target, it observes the actual scroll position and treats the scroll as done once the position stops changing ("settles"). It reacts to what really happens on the page, so it handles a shrinking scrollable area, a scroll lock and a layout shift alike - without a retry, without a fixed target, and noticeably faster (no fixed timeout penalty on every occurrence).

Alternative approach to #678.

Proof

The videos below run all three reproduction cases (shrinking scrollable area, scroll lock, layout shift) back to back - first against the current code, then with this fix.

Before (current code): every case hangs and fails with OperationTimedOut.

2026-06-bug-state.mp4

After (this fix): every case scrolls and returns cleanly, no timeouts.

2026-06-patched-state.mp4

The scroll timeout addressed in chrome-php#678 happens when the page layout
changes between the moment `Mouse::scroll()` computes the target scroll
position and the moment it verifies that position. The verify loop waits
for the page to reach an exact, pre-computed target. Once the layout
shifts mid-scroll, that target can become unreachable and the loop spins
until it fails with OperationTimedOut.

While digging deeper into this I (assisted by AI I have to admit ;))
found several distinct ways to reproduce the issue, each added as a test
case:

- scrollShrink.html - the scrollable area shrinks right after the scroll
  starts.
- scrollLock.html - an overlay/modal locks scrolling (body becomes
  position:fixed), so the maximum scroll distance drops to 0.
- infiniteScroll.html - a lazy-loaded image above the current position
  finishes loading mid-scroll and shifts the layout (the typical
  infinite-scroll case).

The fix proposed in chrome-php#678 (retry once when the recomputed distances
changed) only covers the cases where the maximum scroll distance
changes: it recovers the shrink and the lock case, but not the
layout-shift case. There the page grows, the recomputed distance stays
the same, and it still times out - so that fix unfortunately does not
solve every variant of the issue.

This change takes a different, more robust approach. Instead of waiting
for an exact, pre-computed target, it observes the actual scroll
position and treats the scroll as done once the position stops changing
("settles"). It reacts to what really happens on the page, so it handles
a shrinking scrollable area, a scroll lock and a layout shift alike -
without a retry, without a fixed target, and noticeably faster (no fixed
timeout penalty on every occurrence).

Alternative approach to chrome-php#678.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant