Skip to content

Scroll the element that actually scrolls (issue #61) - #80

Merged
tamnd merged 1 commit into
mainfrom
fix/61-scroll-container
Aug 6, 2026
Merged

Scroll the element that actually scrolls (issue #61)#80
tamnd merged 1 commit into
mainfrom
fix/61-scroll-container

Conversation

@tamnd

@tamnd tamnd commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Fixes the --scroll half of #61.

autoScroll called window.scrollBy. On a site whose body is pinned to the viewport height with the document inside an inner overflow-y:auto container, the window has nothing to scroll, so --scroll did nothing at all. Feishu is built that way, and so are Notion, Linear and most dashboards.

The exit condition was wrong too. It summed the steps it intended to take and stopped once that total reached document.body.scrollHeight. On an app shell that height is one viewport, so the loop gave up after a single step. On an ordinary page it compared intended distance against a height that grows as content loads, and it never checked whether a step actually moved anything.

What it does now:

  • Picks the largest element on the page with a real scroll range and a scrolling overflow-y, falling back to document.scrollingElement. That is the window on a normal page and the inner container on an app shell.
  • Reads scrollTop back after each step instead of assuming the step landed, and steps by 80 percent of the container height rather than a fixed 800px.
  • Stops when the position and the height have both stopped changing for ten ticks, which is what infinite scroll needs, and returns to the top before serialising.
  • Bounds the whole thing by half the render timeout, at least five seconds, so a feed that appends content forever cannot hold a worker. --render-timeout raises it.

Tests are in browser/pool_test.go. TestAutoScrollTriggersLazyContent serves two pages, an app shell and an ordinary tall page, each appending a marker element on scroll, and asserts the marker is in the saved HTML. The app-shell case fails on main and the window case passes, so the ordinary path is covered as a regression. TestAutoScrollLeavesAStaticPageAlone checks that a page with nothing to scroll returns quickly rather than burning its budget, and TestScrollBudget covers the bound. The Chrome-driven ones skip under -short and when no Chrome is found, as the others do.

Not in scope: the virtualised editor case, where a document only ever holds a window of nodes in the DOM and scrolling past them destroys what came before. Capturing that needs incremental DOM collection during the scroll rather than one serialisation at the end, and it is worth its own issue. This change is what makes lazy loading work at all on that class of site.

--scroll called window.scrollBy, which moves nothing on a site whose body
is fixed to the viewport height with the document inside an inner
container. That is how Feishu, Notion, Linear and most dashboards are
built, so --scroll did nothing at all on them and the lazy-loaded content
was never captured.

The loop also stopped once the distance travelled reached
document.body.scrollHeight. On an app shell that is a single viewport, so
it exited after one step, and even on an ordinary page it compared a
running total of intended steps against a height that grows as content
loads.

kage now picks the largest genuinely scrollable element, reads scrollTop
back after each step rather than assuming the step landed, and keeps
going until both the position and the height stop changing. The scroll is
bounded by half the render timeout, at least five seconds, so a page that
appends content forever cannot hold a worker.

The app-shell test fails before this change and the window-scrolled one
passes, so the ordinary case is covered too.
@tamnd
tamnd merged commit a233054 into main Aug 6, 2026
9 checks passed
@tamnd
tamnd deleted the fix/61-scroll-container branch August 6, 2026 08:02
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.

1 participant