Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent browser scroll on HTML5 History popstate

Is it possible to prevent the default behaviour of scrolling the document when a popstate event occurs?

Our site uses jQuery animated scrolling and History.js, and state changes should scroll the user around to different areas of the page whether via pushstate or popstate. The trouble is the browser restores the scroll position of the previous state automatically when a popstate event occurs.

I've tried using a container element set to 100% width and height of the document and scrolling the content inside that container. The problem with that I've found is it doesn't seem to be nearly as smooth as scrolling the document; especially if using lots of css3 like box-shadows and gradients.

I've also tried storing the document's scroll position during a user initiated scroll and restoring it after the browser scrolls the page (on popstate). This works fine in Firefox 12 but in Chrome 19 there is a flicker due to the page being scrolled and restored. I assume this is to do with a delay between the scroll and the scroll event being fired (where the scroll position is restored).

Firefox scrolls the page (and fires the scroll event) before popstate fires and Chrome fires popstate first then scrolls the document.

All the sites I've seen that use the history API either use a solution similar to those above or just ignore the scroll position change when a user goes back/forward (e.g. GitHub).

Is it possible to prevent the document being scrolled at all on popstate events?

like image 636
Alex Malet de Carteret Avatar asked May 24 '12 17:05

Alex Malet de Carteret


People also ask

What triggers Popstate?

The popstate event will be triggered by doing a browser action such as a click on the back or forward button (or calling history. back() or history. forward() in JavaScript). Browsers tend to handle the popstate event differently on page load.

What is history scrollRestoration?

scrollRestoration. The scrollRestoration property of History interface allows web applications to explicitly set default scroll restoration behavior on history navigation.

What is the purpose of the event window Onpopstate?

The window. onpopstate event is fired automatically by the browser when a user navigates between history states that a developer has set. This event is important to handle when you push to history object and then later retrieve information whenever the user presses the back/forward button of the browser.


2 Answers

if ('scrollRestoration' in history) {   history.scrollRestoration = 'manual'; } 

(Announced by Google on September 2, 2015)

Browser support:

Chrome: supported (since 46)

Firefox: supported (since 46)

IE: not supported

Edge: supported (since 79)

Opera: supported (since 33)

Safari: supported

For more info, see Browser compatibility on MDN.

like image 181
Tamás Bolvári Avatar answered Sep 22 '22 01:09

Tamás Bolvári


This has been a reported issue with the mozilla developer core for more than a year now. Unfortunately, the ticket did not really progress. I think Chrome is the same: There is no reliable way to tackle the scroll position onpopstate via js, since it's native browser behaviour.

There is hope for the future though, if you look at the HTML5 history spec, which explicitly wishes for the scroll position to be represented on the state object:

History objects represent their browsing context's session history as a flat list of session history entries. Each session history entry consists of a URL and optionally a state object, and may in addition have a title, a Document object, form data, a scroll position, and other information associated with it.

This, and if you read the comments on the mozilla ticket mentioned above, gives some indication that it is possible that in the near future scroll position will not be restored anymore onpopstate, at least for people using pushState.

Unfortunately, until then, the scroll position gets stored when pushState is used, and replaceState does not replace the scroll position. Otherwise, it would be fairly easy, and you could use replaceState to set the current Scroll position everytime the user has scrolled the page (with some cautious onscroll handler).

Also unfortunately, the HTML5 spec does not specify when exactly the popstate event has to be fired, it just says: «is fired in certain cases when navigating to a session history entry», which does not clearly say if it's before or after; if it was always before, a solution with handling the scroll event occuring after the popstate would be possible.

Cancel the scroll event?

Furthermore, it would also be easy, if the scroll event where cancelable, which it isn't. If it was, you could just cancel the first scroll event of a series (user scroll events are like lemmings, they come in dozens, whereas the scroll event fired by the history repositioning is a single one), and you would be fine.

There's no solution for now

As far as I see, the only thing I'd recommend for now is to wait for the HTML5 Spec to be fully implemented and to roll with the browser behaviour in this case, that means: animate the scrolling when the browser lets you do it, and let the browser reposition the page when there's a history event. The only thing you can influence position-wise is that you use pushState when the page is positioned in a good way to go back to. Any other solution is either bound to have bugs, or to be too browser-specific, or both.

like image 34
Beat Richartz Avatar answered Sep 24 '22 01:09

Beat Richartz