Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I scroll to an element within an overflowed Div?

Tags:

jquery

I have 20 list items inside of a div that can only show 5 at a time. What is a good way to scroll to item #10, and then item #20? I know the height of all the items.

The scrollTo plugin does this, but its source is not super easy to understand without really getting into it. I don't want to use this plugin.

Let's say I have a function that takes 2 elements $parentDiv, $innerListItem, neither $innerListItem.offset().top nor $innerListItem.positon().top gives me the correct scrollTop for $parentDiv.

like image 721
mkoryak Avatar asked Feb 27 '10 02:02

mkoryak


4 Answers

The $innerListItem.position().top is actually relative to the .scrollTop() of its first positioned ancestor. So the way to calculate the correct $parentDiv.scrollTop() value is to begin by making sure that $parentDiv is positioned. If it doesn't already have an explicit position, use position: relative. The elements $innerListItem and all its ancestors up to $parentDiv need to have no explicit position. Now you can scroll to the $innerListItem with:

// Scroll to the top
$parentDiv.scrollTop($parentDiv.scrollTop() + $innerListItem.position().top);

// Scroll to the center
$parentDiv.scrollTop($parentDiv.scrollTop() + $innerListItem.position().top
    - $parentDiv.height()/2 + $innerListItem.height()/2);
like image 133
Glenn Moss Avatar answered Nov 20 '22 18:11

Glenn Moss


This is my own plugin (will position the element in top of the the list. Specially for overflow-y : auto. May not work with overflow-x!):

NOTE: elem is the HTML selector of an element which the page will be scrolled to. Anything supported by jQuery, like: #myid, div.myclass, $(jquery object), [dom object], etc.

jQuery.fn.scrollTo = function(elem, speed) { 
    $(this).animate({
        scrollTop:  $(this).scrollTop() - $(this).offset().top + $(elem).offset().top 
    }, speed == undefined ? 1000 : speed); 
    return this; 
};

If you don't need it to be animated, then use:

jQuery.fn.scrollTo = function(elem) { 
    $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem).offset().top); 
    return this; 
};

How to use:

$("#overflow_div").scrollTo("#innerItem");
$("#overflow_div").scrollTo("#innerItem", 2000); //custom animation speed 

Note: #innerItem can be anywhere inside #overflow_div. It doesn't really have to be a direct child.

Tested in Firefox (23) and Chrome (28).

If you want to scroll the whole page, check this question.

like image 20
lepe Avatar answered Nov 20 '22 19:11

lepe


I've adjusted Glenn Moss' answer to account for the fact that overflow div might not be at the top of the page.

parentDiv.scrollTop(parentDiv.scrollTop() + (innerListItem.position().top - parentDiv.position().top) - (parentDiv.height()/2) + (innerListItem.height()/2)  )

I was using this on a google maps application with a responsive template. On resolution > 800px, the list was on the left side of the map. On resolution < 800 the list was below the map.

like image 36
KPheasey Avatar answered Nov 20 '22 20:11

KPheasey


The above answers will position the inner element at the top of the overflow element even if it's in view inside the overflow element. I didn't want that so I modified it to not change the scroll position if the element is in view.

jQuery.fn.scrollTo = function(elem, speed) {
    var $this = jQuery(this);
    var $this_top = $this.offset().top;
    var $this_bottom = $this_top + $this.height();
    var $elem = jQuery(elem);
    var $elem_top = $elem.offset().top;
    var $elem_bottom = $elem_top + $elem.height();

    if ($elem_top > $this_top && $elem_bottom < $this_bottom) {
        // in view so don't do anything
        return;
    }
    var new_scroll_top;
    if ($elem_top < $this_top) {
        new_scroll_top = {scrollTop: $this.scrollTop() - $this_top + $elem_top};
    } else {
        new_scroll_top = {scrollTop: $elem_bottom - $this_bottom + $this.scrollTop()};
    }
    $this.animate(new_scroll_top, speed === undefined ? 100 : speed);
    return this;
};
like image 6
mike Avatar answered Nov 20 '22 18:11

mike