Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where in the Javascript event chain does the browser's "return to original position" occur following refresh?

I have a busy webpage with lots of widgets. It takes a second or two to load sometimes.

When I hit refresh from some location other than the top of the page, I can see that the page loads as if scrollTop==0 and at some point snaps back to my original position.

The problem is that I have various initializations that occur in a .ready() event handler, some of which rely on scrollTop and scrollLeft. These initializations occur before the document has returned to it's original position, which then give nonsensical results from the original position.

Wrapping these initializations inside a .load() event handler doesn't seem to work, either. What does work is adding a (fairly long) delay via setTimeout inside the .load() handler. This is undesirable for obvious reasons.

This suggests that the "return to original position" happens independently of the standard event chains, ie. is not specified in the ECMA standards or is browser-implementation dependent.

What is the best way to deal with initializations that need to happen only after the browser has returned to the original position? Is there an associated event? Is there some way to recognize that a refresh has occurred and only delay in that case?

All of my testing has been in Chrome and Firefox.

like image 969
jordanpg Avatar asked Jan 17 '13 18:01

jordanpg


2 Answers

The "return to original position" behavior is a feature that browsers have added as a bonus, not one that is standardized. I don't think that there is a specific event that is a "browser has scrolled because of a page refresh" event.

However, if the browser is behaving properly, I suspect it should fire an onscroll event on the window when it scrolls. This will necessarily be after the page load event (because otherwise the browser has nothing to scroll to, so I would look for the scroll event after the load event and infer that the page has been scrolled by the browser.

Keep in mind you'll have to successfully handle the case where the page is not refreshed and you don't get an onscroll event. Therefore, what I would do (if possible) is to assume that the page is not scrolled, and then if you do get the onscroll event, start over again by repositioning with the new location in mind. There's a bit of a "flash" there where things are loading and then reloading, but this will handle the asynchronous nature of the callbacks.

like image 176
Matt Avatar answered Sep 28 '22 00:09

Matt


Since this isn't a standard event (as you were saying), I would suggest creating a little system that can do a quick repetive test for you to ensure that after a load/refresh you are currently above that 0 point, and to then run any code for your widgets, etc.

var scrollTopInterval;

$(window).load(function () {
  var i = 0;

  scrollTopInterval = setInterval( function () {
    console.log( $(window).scrollTop() );

    if ($(window).scrollTop() > 0) {
      weAreReady(); // do stuff, we are ready to go
      clearInterval(t);
    }

    i++;

    // 2 seconds might be way too much (but you said you needed a long delay)
    if (i >= 2000) { clearInterval(scrollTopInterval); }
  }, 1);
});

function weAreReady() {
   alert('we moved down past 0 after refresh');
}

Additionally lets make sure we clear out this interval if the user starts scrolling at all (could of just been the first time the page is loaded, etc);

$(window).scroll(function () { 
   clearInterval(scrollTopInterval);
});

Here is the jsFIddle of this, of course you can't refresh in jsFiddle, so just copy past the code into an html file or something (that's how I was doing my testing).

It seemed to work, if you were already at the top of the page everything was fine, and if you are further down you see the 0 pop up then the higher number and you are immediately alerted (where we call our function to run the rest of the page).

like image 43
Mark Pieszak - Trilon.io Avatar answered Sep 27 '22 22:09

Mark Pieszak - Trilon.io