Open Bug 2080530 Opened 11 days ago Updated 8 days ago

Navigation API: scroll "after-transition" restore on an intercepted traversal uses stale layout when the intercept handler changed the page height

Categories

(Core :: DOM: Navigation, defect)

Firefox 157
defect

Tracking

()

UNCONFIRMED

People

(Reporter: simrpgman, Unassigned)

References

(Blocks 1 open bug)

Details

Attachments

(1 file)

Attached file scroll-restore.html —

Steps to reproduce

Product / Component: Core :: DOM: Navigation
Version: 157 Branch (the Release build used)
Platform: ARM64 / macOS

Summary: Navigation API: scroll "after-transition" restore on an intercepted traversal uses stale layout when the intercept handler changed the page height

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:157.0) Gecko/20100101 Firefox/157.0 (also reproduced on Nightly 160.0a1, build ID 20261010084543)

Steps to reproduce:

  1. Save the attached scroll-restore.html and serve it over http (for example npx http-server).
  2. Open it. The page is 5000px tall and scrolls to 1000. It navigates with navigation.navigate('?pushed'), and the intercepted push's handler sets the content height to 0. It then calls navigation.back(). The intercepted traversal's handler (default scroll: "after-transition") waits 20 ms, then sets the height back to 5000px without reading layout.
  3. Read the log: scrollY when back().finished settles, and 100 ms later.
  4. Repeat with ?render=microtask (the height is restored a microtask into the handler), with ?framed (the same page in an iframe), and with ?flush=1 (the handler reads document.documentElement.scrollHeight at the end).

Actual results

Actual results:

  • Top level: scrollY is 0 when finished settles. It becomes 1000 within 100 ms with the 20 ms render. With the microtask render it stays 0 in most runs.
  • In an iframe: scrollY stays 0. (On Nightly, the iframe run with the 20 ms render crashes the tab instead; that is a separate bug about the traversal being committed twice in an iframe, filed alongside. ?framed&render=microtask shows the scroll bug on Nightly.)
  • With ?flush=1: scrollY is 1000 at finished in every case.

Expected results

Expected results:

scrollY is 1000 when finished settles, at top level and in an iframe, with or without the layout read, as in Chrome. Per HTML, the handler's promise settling runs "finish a NavigateEvent", then "process scroll behavior", then "restore scroll position data", all before the finished promises resolve. By then the document is 5000px tall again, so the restore should not clamp to the old 0px range.

Additional information:

  • Reproduced on Release 157.0.1, Beta 158.0b5, Developer Edition 158.0b5 and Nightly 160.0a1 (macOS arm64), with new profiles, headless and headed.
  • Reading document.documentElement.scrollHeight at the end of the handler works around it, which points at the restore using layout from before the handler's style change. Bug 217120 was the same kind of problem on the classic history path.
  • Related: bug 1950894 (Navigation API tracker; this should probably block it) and bug 2050964 (fixed the "has been scrolled by the user" check in the same restore step).
  • Not covered by WPT: navigation-api/scroll-behavior/after-transition-traverse-no-fragment.html never changes the page height during the navigation. A variant that shrinks the page on push and grows it back in the traverse handler, run at top level and in an iframe, would catch this.
  • Real-world impact: a router that renders the destination view inside the intercept handler (ui-router's Navigation API location plugin, with its interceptTraverse option) loses the back/forward scroll position unless it forces layout itself.

The Bugbug bot thinks this bug should belong to the 'Core::DOM: Navigation' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.

Component: Untriaged → DOM: Navigation
Product: Firefox → Core
Severity: -- → S3
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: