Scrolling to the next element

Arrowcatch picture Arrowcatch · Sep 8, 2012 · Viewed 18.8k times · Source

I'm struggling with a jquery or javascript problem.

It already got annoying which tells me I might think too complicated on this one.

So my markup (simplyfied) looks like this:

<div class="container">
    My Content
<a href="#" class="button">scroll down</a>
</div>


<div class="container">
    My Content
<a href="#" class="button">scroll down</a>
</div>


<div class="container">
    My Content
<a href="#" class="button">scroll down</a>
</div>


<div class="container">
    My Content
<a href="#" class="button">scroll down</a>
</div>

Basically just some containers.

Each one contains different content and a button.


The Plan:

1) After a click on a button the window should scroll down to the next container.

2) The last button scrolls to the first container again. So I need a loop.

3) The numbers of containers may change from page to page.

EDIT: 4) The containers may not always be direct siblings to each other (see markup below)


The Problem:

I could get this to work by giving each container a unique ID as a target for the scroll effect.

The problem with that is that it gets too messy quickly.

Cant I just somehow target "the next object with the class: container", and scroll to that?


I'm not sure if js or jquery is the right approach. My knowledge in both is somewhat limited.

I would be really grateful for a push in the right direction.


EDIT: The containers may not always be direct siblings of each other.

<div class="row">
        <div class="container">
            My Content
        <a href="#" class="button">scroll down</a>
        </div>


        <div class="container">
            My Content
        <a href="#" class="button">scroll down</a>
        </div>
</div>        

        <div class="container">
            My Content
        <a href="#" class="button">scroll down</a>
        </div>


        <div class="container">
            My Content
        <a href="#" class="button">scroll down</a>
        </div>

<div class="row">
        <div class="container">
            My Content
        <a href="#" class="button">scroll down</a>
        </div>


        <div class="container">
            My Content
        <a href="#" class="button">scroll down</a>
        </div>
</div>  

Answer

ronalchn picture ronalchn · Sep 8, 2012

Simple solution:

To get the next container, try using next().

Basically, the <div> containers are siblings of each other, so calling .next() on one div container will give you the next.

$(".button").on("click", function(e) {
    $(document).scrollTop($(this).parent().next().offset().top);
    // $(this).parent().next() // this is the next div container.
    return false; // prevent anchor
});

http://jsfiddle.net/Pm3cj/1/

You just use $(this) to get the link object, .parent() to get the parent of the link, which is the <div>, then .next() to get the next sibling (note it will wrap automatically, so the sibling after the last <div> is the first <div>!),.offset()to get its position relative to the page,.top` to get it relative to the top border.

Then you just use $(document).scrollTop() to scroll to that location.


For a completely general solution, use:

$(".button").on("click", function(e) {
    container = $(this).parent();

    // if I am the last .container in my group...
    while (    document != container[0] // not reached root
            && container.find('~.container, ~:has(.container)').length == 0)
        container = container.parent(); // search siblings of parent instead

    nextdiv = container.nextAll('.container, :has(.container)').first();

    // no next .container found, go back to first container
    if (nextdiv.length==0) nextdiv = $(document).find('.container:first');

    $(document).scrollTop(nextdiv.offset().top);
    // $(this).parent().next() // this is the next div container.
    return false;
});

​The code basically uses container.find('~.container, ~:has(.container)') to find any sibling that has or is a .container. If nothing, then go up the DOM tree 1 step.

After it finds something which is or has a .container, it grabs it with nextdiv = container.nextAll('.container, :has(.container)').first();.

Lastly, if nothing is found, checked by nextdiv.length==0, just grab the first .container in the whole page.

Then scroll to whatever .container was grabbed.

http://jsfiddle.net/Pm3cj/3/


To animate the scroll, place the scrollTop property in an animate function:

// $(document).scrollTop(nextdiv.offset().top); // snaps to new scroll position
$('body').animate({scrollTop:nextdiv.offset().top},300); // animates scrolling

http://jsfiddle.net/Pm3cj/4/