How can I retain the scroll position of a scrollable area when pressing back button?
Asked Answered
U

8

33

I have a long list of links inside a big scrollable div. Each time when a user click on a link then click the back button, it starts at the very top of the div. It is not user friendly to our users. Any ways to let the browser scroll to the previous position when pressing the back button?

Thank you very much!

Unreligious answered 23/3, 2015 at 4:33 Comment(2)
Check this link ... #2009529Reichstag
store the position in cookies and after that use the cookie to scroll the page to exact position .Jocular
E
30

During page unload, get the scroll position and store it in local storage. Then during page load, check local storage and set that scroll position. Assuming you have a div element with id element. In case it's for the page, please change the selector :)

$(function() {
   $(window).unload(function() {
      var scrollPosition = $("div#element").scrollTop();
      localStorage.setItem("scrollPosition", scrollPosition);
   });
   if(localStorage.scrollPosition) {
      $("div#element").scrollTop(localStorage.getItem("scrollPosition"));
   }
});
Enid answered 23/3, 2015 at 4:47 Comment(11)
Thanks! It's good, but still one little thing. When clicking back, the browser initial starts at the top, and jump to the position after 0.5 seconds. Any way to shorten the time lapse so that it looks smoother?Unreligious
It's because the code executes after the dom is loaded. That's why there is a delay. Instead of placing the code in domContent loaded. You can try $("div#element").load(function() {}) and place the element outside the document ready handler.Enid
Also, if a user scroll down the page, then leave the page, and go back to the page again, it should be a new start for him so it should start at the top. But now it also remembers the previous position. Any way to prevent this? :)Unreligious
Add one more condition, Check $(window).scrollTop(); and see if it's above 650. In that case don't store the scrollPosition in the local storage :)Enid
Also if the $(window).scrollTop(); is above 650, remove the scrollPosition from local storage as well.Enid
@Enid Why 650?Emptyhanded
@Timo OP wanted to clear the scroll position when the user scrolls below a certain point so that next time again the page will start from the beginning.. That's what I remember from the last messages ;)Enid
@mohamedrias, very usefulTartrate
can someone provide any vanilla versions that match 2019s compatibility? :DHamamelidaceous
Thanks @Enid you save my day!Blowtorch
It seems like the website javascript.info saves the scroll position without using localSotage. Any idea how to achieve that?Fauna
P
18

I think we should save scroll data per page, also we should use session storage instead of local storage since session storge effects only the current tab while local storage shared between all tabs and windows of the same origin

$(function () {
            var pathName = document.location.pathname;
            window.onbeforeunload = function () {
                var scrollPosition = $(document).scrollTop();
                sessionStorage.setItem("scrollPosition_" + pathName, scrollPosition.toString());
            }
            if (sessionStorage["scrollPosition_" + pathName]) {
                $(document).scrollTop(sessionStorage.getItem("scrollPosition_" + pathName));
            }
        });
Postobit answered 28/9, 2017 at 4:31 Comment(2)
Yes - this is super important. Saving the pathname in sessionStorage is exactly what is needed here.Demean
Doesn't work on iPhone with Safari for me.Markitamarkka
A
5

I had the same problem with a simple user interface consisting of a fixed menu div and a scrolling document div ("pxeMainDiv" in the code example below). The following solution worked for me in Chrome 47.0.2526.106 m and in Firefox 43.0.3. (My application is for use in-house and I did not need to cater for old versions of IE).

$(document).ready(function(){
    if (history.state) {
       $("#pxeMainDiv").scrollTop(history.state.data);
    }
    $("#pxeMainDiv").scroll(function() {
       var scrollPos = $("#pxeMainDiv").scrollTop();
       var stateObj = { data: scrollPos };
       history.replaceState(stateObj, "");
    });
});

On the div scroll event, the scroll position of the div is stored in the state object inside the browser history object. Following a press of the Back button, on the document ready event, the scroll position of the div is restored to the value retrieved from the history.state object.

This solution should work for the reverse navigation of an arbitrarily long chain of links.

Documentation here: https://developer.mozilla.org/en-US/docs/Web/API/History_API

Aquiver answered 6/1, 2016 at 13:18 Comment(1)
Without jQuery: if (history.state) window.scrollTo(0, history.state.scrollY); and window.onscroll = e => history.replaceState({ scrollY: window.scrollY }, "");Execrative
C
5

When using window.history.back(), this is actually default browser functionality as user SD. has pointed out.

On a site I am currently building, I wanted the logo of the company to backlink to the index page. Since jQuery 3, $(window).unload(function() should be rewritten to $(window).on('unload', function(). My code looks like this (using Kirby CMS' php syntax):

<?php if ($page->template() == 'home'): ?>

<script>

$(function() {
 $(window).on("unload", function() {
    var scrollPosition = $(window).scrollTop();
    localStorage.setItem("scrollPosition", scrollPosition);
 });
 if(localStorage.scrollPosition) {
    $(window).scrollTop(localStorage.getItem("scrollPosition"));
 }
});

</script>
Counterstatement answered 28/12, 2018 at 15:28 Comment(0)
C
4

For anyone coming from react or anything similar to react router, here are two simple functions:

export function saveScrollPosition(context: any) {
  let path = context.router.route.location.pathname;
  let y = window.scrollY;
  sessionStorage.setItem("scrollPosition_" + path, y.toString());
}

export function restoreScrollPosition(context: any) {
  let path = context.router.route.location.pathname;
  let y = Number(sessionStorage.getItem("scrollPosition_" + path));
  window.scrollTo(0, y);
}
Contracted answered 2/2, 2021 at 18:11 Comment(1)
it would've been great to know how to use these.Kenric
D
2

With History api you can utilize scrollRestoration and stop browser from resetting scroll position.

Read it here. https://developers.google.com/web/updates/2015/09/history-api-scroll-restoration

Dorset answered 16/1, 2021 at 16:53 Comment(0)
N
0

If a back button is kind of history back button window.history.back() Then what you are seeking for, is a default browser functionality. So you don't have to worry about it.

If your back button actually point to some URL in your application via link or form, then you have to take care that manually.

For solution you may use cookies to store your page scroll value. Each time user scroll on your page, do save scroll value for that page to cookie. Extra work is applied to manual cookie management.

window.onScroll = function(){
    document.cookie="pageid=foo-"+window.scrollY+";";
}

This cookie value can be use to set scroll value of the page on page visit.

window.scroll(0,cookievalue);
Nip answered 23/3, 2015 at 4:53 Comment(1)
if page build complete after page load event the default functionality will not workTrixy
D
0

/* Use the below code to restore the scroll position of individual items and set focus to the last clicked item. */

(function ($)
{

    if (sessionStorage)
        $.fn.scrollKeeper = function (options)
        {
            var defauts =
            {
                key: 'default'
            };
            var params = $.extend(defauts, options);

            var key = params.key;
            var $this = $(this);

            if (params.init === true)
            {
                var savedScroll = sessionStorage.getItem(key);

                if (typeof savedScroll != 'undefined')
                {
                    var int_savedScroll = parseInt(savedScroll);
                    if (int_savedScroll > 0)
                        $this.scrollTop(int_savedScroll);

                    setTimeout(function ()
                    {
                        var selectorFocus = sessionStorage.getItem(key + "-focus");
                        if (selectorFocus && selectorFocus != "")
                            $(document.querySelector(selectorFocus)).focus();
                    }, 100, key);
                }
            }

            window.addEventListener("beforeunload", function () 
            {
                sessionStorage.setItem(key, $this.scrollTop());
                if (document.activeElement)
                {
                    var selectorFocus = elemToSelector(document.activeElement);

                    if (selectorFocus)
                        sessionStorage.setItem(key + "-focus", selectorFocus);
                    else
                        sessionStorage.setItem(key + "-focus", "");
                }
                else
                    sessionStorage.setItem(key + "-focus", "");

            });
        };


    function elemToSelector(elem)   /* written by Kévin Berthommier */
    {
        const {
            tagName,
            id,
            className,
            parentNode
        } = elem;

        if (tagName === 'HTML') return 'HTML';

        let str = tagName;

        str += (id !== '') ? `#${id}` : '';

        if (className)
        {
            const classes = className.split(/\s/);
            for (let i = 0; i < classes.length; i++)
            {
                if(typeof classes[i] === 'string' && classes[i].length > 0)
                    str += `.${classes[i]}`;
            }
        }

        let childIndex = 1;

        for (let e = elem; e.previousElementSibling; e = e.previousElementSibling)
        {
            childIndex += 1;
        }

        str += `:nth-child(${childIndex})`;

        return `${elemToSelector(parentNode)} > ${str}`;
    }

})(jQuery);

/* Usage:

$('#tab1div').scrollKeeper({ key: 'uniq-key1', init: true });

If you don't need to restore the scroll positions (for example for restart), and you need just to save the scroll positions for the next time, use:

$('#tab1div').scrollKeeper({ key: 'uniq-key1', init: false }); */

Demented answered 23/11, 2021 at 18:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.