Question

i tried to make a custom scrolling script that goes from one block to another in my website but when i click on my next button, the scrolling always jump to the top. I don't know why it always do that.

Here is my javascript code :

function myscroll(i)
{
    if (document.body.scrollTop + window.innerHeight > document.body.scrollHeight - 50)
    {
        document.body.scrollTop += 1;
        if (document.body.scrollTop + window.innerHeight < document.body.scrollHeight)
            setTimeout(function() { myscroll(i) }, 10);
    }
    else if (document.body.scrollTop < i - 100)
    {
        document.body.scrollTop += 10;
        if (document.body.scrollTop + window.innerHeight < document.body.scrollHeight)
            setTimeout(function() { myscroll(i) }, 10);
    }
    else if (document.body.scrollTop < i - 50)
    {
        document.body.scrollTop += 5;
        if (document.body.scrollTop + window.innerHeight < document.body.scrollHeight)
            setTimeout(function() { myscroll(i) }, 10);
    }
    else if (document.body.scrollTop < i)
    {
        document.body.scrollTop += 1;
        if (document.body.scrollTop + window.innerHeight < document.body.scrollHeight)
            setTimeout(function() { myscroll(i) }, 10);
    }
}

here i made an exemple on jsbin : http://jsbin.com/ehIZAya/

Thanks for reading.

Was it helpful?

Solution

Problem: Page jumping to top

The page jumps to the top because href="#" causes your browser to look for an element with ID of what comes after the #. For example:

  • This link is equivalent to href="#20898954" (since 20898954 is the ID of this answer); will cause your browser to jump to the top of this answer
  • This link is equivalent to href="#"; it will cause your browser to jump to the top of the page

To fix this, you have two choices:

  1. Remove each anchor's href attribute. Unfortunately, this method removes all styling (and it looks like ordinary text), which can be confusing. Instead, I prefer to...
  2. Handle the click event itself in the onclick function with preventDefault().

Problem: document.body.scrollTop always equals 0. In your code, the first else if executes as an infinite loop, since it is the first condition that evaluates to true. The problem is that you add pixels to document.body.scrollTop, which remains 0, and thus, the second condition always, in effect, calls itself to run again.

Replace document.body.scrollTop with document.documentElement.scrollTop for accurate readings of the current top of the viewable window, and to set it correctly.


To prevent the automatic jump to the top of the page, you can use preventDefault(). Assume each anchor has class link:

var links = document.getElementsByClassName("link")
for (var i = 0; i < links.length; i++) {
    links[i].onclick = function(e) {
        e.preventDefault();
        myscroll(someNumber);
    };
};

The problem there is someNumber. You could enter an integer value (i.e. 500), and each link would scroll to the same place on the page (500px). You could enter an integer * i (i.e. 500 * i), and each link would scroll to a multiple of 500px (0px, 500px, 1000px, etc.). But I chose to make this a little more customizable than that, with a custom attribute called scroll-target.

Each anchor is defined <a class="link" href="#" scroll-target="500">, where 500 might be any value. To get a custom attribute, use element.getAttribute("attributeName"). And so, we're left with:

for (var i = 0; i < links.length; i++) {
    links[i].onclick = function(e) {
        e.preventDefault();
        myscroll(this.getAttribute("scroll-target"));
    };
};

To apply this to your code, make sure each anchor is defined <a class="link" href="#" scroll-target="500">, replacing 500 with the actual value you want. You can also use a class name other than "link", but if you do, make sure you replace the class name in the second line of my script also.

On page load, it alerts a few values. Scroll to random places, and refresh the page. Take note which values change, and which remain the same. Do this a few times until you understand.

Javascript:

alert("document.body.scrollTop = " + document.body.scrollTop + "\ndocument.documentElement.scrollTop = " + document.documentElement.scrollTop + "\ndocument.body.scrollHeight = " + document.body.scrollHeight + "\nwindow.innerHeight = " + window.innerHeight);
var links = document.getElementsByClassName("link")
for (var i = 0; i < links.length; i++) {
    links[i].onclick = function(e) {
        e.preventDefault();
        myscroll(this.getAttribute("scroll-target"));
    };
};

function myscroll(i) {
    // If bottom of currently viewable area is less than 50px from bottom of page
    if (document.documentElement.scrollTop + window.innerHeight > document.body.scrollHeight - 50) {
        console.log("1");
        document.documentElement.scrollTop += 1;
        if (document.documentElement.scrollTop + window.innerHeight < document.body.scrollHeight)
            setTimeout(function () {
                myscroll(i)
            }, 10);
    // If top of currently viewable area is 101px or more above target
    } else if (document.documentElement.scrollTop < i - 100) {
        console.log("2");
        document.documentElement.scrollTop += 10;
        if (document.documentElement.scrollTop + window.innerHeight < document.body.scrollHeight)
            setTimeout(function () {
                myscroll(i)
            }, 10);
    // If top of currently viewable area is 51-100px above target
    } else if (document.documentElement.scrollTop < i - 50) {
        console.log("3");
        document.documentElement.scrollTop += 5;
        if (document.documentElement.scrollTop + window.innerHeight < document.body.scrollHeight)
            setTimeout(function () {
                myscroll(i)
            }, 10);
    // If top of currently viewable area is 49px or less above target (including below target)
    } else if (document.documentElement.scrollTop < i) {
        console.log("4");
        document.documentElement.scrollTop += 1;
        if (document.documentElement.scrollTop + window.innerHeight < document.body.scrollHeight)
            setTimeout(function () {
                myscroll(i)
            }, 10);
    }
}

You might also want to add equal and opposite conditions for the top of the currently-viewable area being past/below the target, if you ever want to scroll upwards.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top