Current browsers do not handle scroll restoration properly for Single Page Apps.
The desired behavior on popstate event (back or forward button was triggered) is to recover whatever scrolling position each scrollable element on the page had(ScrollTop and ScrollLeft).
On pushState( i.e. when a new page is being visited), we would like to ScrollToTop (and perhaps ScrollToLeft) scrollable elements (which ones, though? wrt nested navigation).
Requirements and Implications
History.scrollRestoration should be set to 'manual'
should be able to differentiate between popstate route change and pushstate route change (unnecessary?)
each scrollable element needs to record its scrolling position(ScrollTop and ScrollLeft values) in sessionStorage
handle focus for accessibility (which element should be focused when the page is scrolled to Top?)
on page reload, restore scrolling position
handle nested overflow element scroll behaviour when accessed via nested route
Proposed implementation
It should be sufficient to define a transformative function func(*ui.Element)*ui.Element that would register a scrollevent listener on "FirstTimeMounted". However this event listener shall not be registered indiscriminately: the corresponding DOM element computedStyles should include an overflowor overflow-x or overflow-y set to scrollor auto.
Checking the computed styles could be done after mounting.
On scroll, retrieve scrollTopand scrollLeft and store these values.
storage of the scroll offsets
These offsets are part of the User Interface state. They could be stored in session storage or in the History object.
The datastructure is likely to be aui.Object storing ui.Object equivalent to a map[id]map[offsetType]OffsetValue with id and offsetType being string types and OffsetValue being a numeric type.
A priori, History object storage will be chosen as it can already handle multiple pages.
However, it requires to change the current implementation that does not have a way to store data/state for each entry.
scroll restoration
The current route / browser URL being the serialized representation of the application state, which includes the User Interface state, we should determine and apply the relevant scroll offsets on route change.
The causes for route change are threefold:
Back button has been hit or Forward button has been hit (popstateevent)
F5 (page refresh) has been triggered
A link has been hit (or navigation has been programatically triggered) (call tohistory.pushState)
In case 1, we should just restore the scrolling offsets that have been prealably stored in the history. Unmounted elements should be reset to zero (scrollTop,scrollLeft =0,0)
In case 2, we would like to restore the scrolling offsets (they may be in the history but I am not sure yet)
In case 3, already activated ViewElements do not remount. Otherwise, mounted Elements were previously unmounted which means reset. We just store the scrolling values.
Henceforth, on unmount(ed?), we should reset the scrolling offsets. On mount(ed?), if element is scrollable, restore scrolloffsets.
Other considerations
document.scrollingElement should be used to find out about whether <html> or <body> holds the outermost scrolling behaviour of any given page.
focus management should also be consistent with the scrolling behaviour adopted
Problem Statement
Current browsers do not handle scroll restoration properly for Single Page Apps.
The desired behavior on popstate event (back or forward button was triggered) is to recover whatever scrolling position each scrollable element on the page had(ScrollTop and ScrollLeft). On pushState( i.e. when a new page is being visited), we would like to ScrollToTop (and perhaps ScrollToLeft) scrollable elements (which ones, though? wrt nested navigation).
Requirements and Implications
should be able to differentiate between popstate route change and pushstate route change(unnecessary?)Proposed implementation
It should be sufficient to define a transformative function
func(*ui.Element)*ui.Element
that would register ascroll
event listener on "FirstTimeMounted". However this event listener shall not be registered indiscriminately: the corresponding DOM element computedStyles should include anoverflow
oroverflow-x
oroverflow-y
set toscroll
orauto
. Checking the computed styles could be done aftermounting
. On scroll, retrievescrollTop
andscrollLeft
and store these values.storage of the scroll offsets
These offsets are part of the User Interface state. They could be stored in session storage or in the History object.
The datastructure is likely to be a
ui.Object
storingui.Object
equivalent to amap[id]map[offsetType]OffsetValue
with id and offsetType being string types and OffsetValue being a numeric type.A priori, History object storage will be chosen as it can already handle multiple pages. However, it requires to change the current implementation that does not have a way to store data/state for each entry.
scroll restoration
The current route / browser URL being the serialized representation of the application state, which includes the User Interface state, we should determine and apply the relevant scroll offsets on route change. The causes for route change are threefold:
popstate
event)history.pushState
)In case 1, we should just restore the scrolling offsets that have been prealably stored in the history. Unmounted elements should be reset to zero (
scrollTop,scrollLeft =0,0
) In case 2, we would like to restore the scrolling offsets (they may be in the history but I am not sure yet) In case 3, already activated ViewElements do not remount. Otherwise, mounted Elements were previously unmounted which means reset. We just store the scrolling values.Henceforth, on unmount(ed?), we should reset the scrolling offsets. On mount(ed?), if element is scrollable, restore scrolloffsets.
Other considerations
document.scrollingElement
should be used to find out about whether<html>
or<body>
holds the outermost scrolling behaviour of any given page.