[javascript] How do I get an element to scroll into view, using jQuery?

I have an HTML document with images in a grid format using <ul><li><img.... The browser window has both vertical & horizontal scrolling.

Question: When I click on an image <img>, how then do I get the whole document to scroll to a position where the image I just clicked on is top:20px; left:20px ?

I've had a browse on here for similar posts...although I'm quite new to JavaScript, and want to understand how this is achieved for myself.

This question is related to javascript jquery

The answer is


Here's a quick jQuery plugin to map the built in browser functionality nicely:

$.fn.ensureVisible = function () { $(this).each(function () { $(this)[0].scrollIntoView(); }); };

...

$('.my-elements').ensureVisible();

Simple 2 steps for scrolling down to end or bottom.

Step1: get the full height of scrollable(conversation) div.

Step2: apply scrollTop on that scrollable(conversation) div using the value obtained in step1.

var fullHeight = $('#conversation')[0].scrollHeight;

$('#conversation').scrollTop(fullHeight);

Above steps must be applied for every append on the conversation div.


After trying to find a solution that handled every circumstance (options for animating the scroll, padding around the object once it scrolls into view, works even in obscure circumstances such as in an iframe), I finally ended up writing my own solution to this. Since it seems to work when many other solutions failed, I thought I'd share it:

function scrollIntoViewIfNeeded($target, options) {

    var options = options ? options : {},
    $win = $($target[0].ownerDocument.defaultView), //get the window object of the $target, don't use "window" because the element could possibly be in a different iframe than the one calling the function
    $container = options.$container ? options.$container : $win,        
    padding = options.padding ? options.padding : 20,
    elemTop = $target.offset().top,
    elemHeight = $target.outerHeight(),
    containerTop = $container.scrollTop(),
    //Everything past this point is used only to get the container's visible height, which is needed to do this accurately
    containerHeight = $container.outerHeight(),
    winTop = $win.scrollTop(),
    winBot = winTop + $win.height(),
    containerVisibleTop = containerTop < winTop ? winTop : containerTop,
    containerVisibleBottom = containerTop + containerHeight > winBot ? winBot : containerTop + containerHeight,
    containerVisibleHeight = containerVisibleBottom - containerVisibleTop;

    if (elemTop < containerTop) {
        //scroll up
        if (options.instant) {
            $container.scrollTop(elemTop - padding);
        } else {
            $container.animate({scrollTop: elemTop - padding}, options.animationOptions);
        }
    } else if (elemTop + elemHeight > containerTop + containerVisibleHeight) {
        //scroll down
        if (options.instant) {
            $container.scrollTop(elemTop + elemHeight - containerVisibleHeight + padding);
        } else {
            $container.animate({scrollTop: elemTop + elemHeight - containerVisibleHeight + padding}, options.animationOptions);
        }
    }
}

$target is a jQuery object containing the object you wish to scroll into view if needed.

options (optional) can contain the following options passed in an object:

options.$container - a jQuery object pointing to the containing element of $target (in other words, the element in the dom with the scrollbars). Defaults to the window that contains the $target element and is smart enough to select an iframe window. Remember to include the $ in the property name.

options.padding - the padding in pixels to add above or below the object when it is scrolled into view. This way it is not right against the edge of the window. Defaults to 20.

options.instant - if set to true, jQuery animate will not be used and the scroll will instantly pop to the correct location. Defaults to false.

options.animationOptions - any jQuery options you wish to pass to the jQuery animate function (see http://api.jquery.com/animate/). With this, you can change the duration of the animation or have a callback function executed when the scrolling is complete. This only works if options.instant is set to false. If you need to have an instant animation but with a callback, set options.animationOptions.duration = 0 instead of using options.instant = true.


Simplest solution I have seen

var offset = $("#target-element").offset();
$('html, body').animate({
    scrollTop: offset.top,
    scrollLeft: offset.left
}, 1000);

Tutorial Here


Have a look at the jQuery.scrollTo plugin. Here's a demo.

This plugin has a lot of options that go beyond what native scrollIntoView offers you. For instance, you can set the scrolling to be smooth, and then set a callback for when the scrolling finishes.

You can also have a look at all the JQuery plugins tagged with "scroll".


Just a tip. Works on firefox only

Element.scrollIntoView();


There's a DOM method called scrollIntoView, which is supported by all major browsers, that will align an element with the top/left of the viewport (or as close as possible).

$("#myImage")[0].scrollIntoView();

On supported browsers, you can provide options:

$("#myImage")[0].scrollIntoView({
    behavior: "smooth", // or "auto" or "instant"
    block: "start" // or "end"
});

Alternatively, if all the elements have unique IDs, you can just change the hash property of the location object for back/forward button support:

$(document).delegate("img", function (e) {
    if (e.target.id)
        window.location.hash = e.target.id;
});

After that, just adjust the scrollTop/scrollLeft properties by -20:

document.body.scrollLeft -= 20;
document.body.scrollTop -= 20;

There are methods to scroll element directly into the view, but if you want to scroll to a point relative from an element, you have to do it manually:

Inside the click handler, get the position of the element relative to the document, subtract 20 and use window.scrollTo:

var pos = $(this).offset();
var top = pos.top - 20;
var left = pos.left - 20;
window.scrollTo((left < 0 ? 0 : left), (top < 0 ? 0 : top));

After trial and error I came up with this function, works with iframe too.

function bringElIntoView(el) {    
    var elOffset = el.offset();
    var $window = $(window);
    var windowScrollBottom = $window.scrollTop() + $window.height();
    var scrollToPos = -1;
    if (elOffset.top < $window.scrollTop()) // element is hidden in the top
        scrollToPos = elOffset.top;
    else if (elOffset.top + el.height() > windowScrollBottom) // element is hidden in the bottom
        scrollToPos = $window.scrollTop() + (elOffset.top + el.height() - windowScrollBottom);
    if (scrollToPos !== -1)
        $('html, body').animate({ scrollTop: scrollToPos });
}

My UI has a vertical scrolling list of thumbs within a thumbbar The goal was to make the current thumb right in the center of the thumbbar. I started from the approved answer, but found that there were a few tweaks to truly center the current thumb. hope this helps someone else.

markup:

<ul id='thumbbar'>
    <li id='thumbbar-123'></li>
    <li id='thumbbar-124'></li>
    <li id='thumbbar-125'></li>
</ul>

jquery:

// scroll the current thumb bar thumb into view
heightbar   = $('#thumbbar').height();
heightthumb = $('#thumbbar-' + pageid).height();
offsetbar   = $('#thumbbar').scrollTop();


$('#thumbbar').animate({
    scrollTop: offsetthumb.top - heightbar / 2 - offsetbar - 20
});