Scroll to element only if not in view - jQuery
Yes there is a jQuery plugin that scrolls to an element only if it's not within visible boundaries of the scrollable ancestor. I've written one does exactly what you require. And you will probably find it easier to use compared to scrollTo()
since you only have to provide the element that you'd like to see.
I could copy paste the code here, but since I add some additions from time to time it's better to link you to blog post where you'll find all the details related to programmatic scrolling and latest plugin code. Programmatic scrolling can be quite distracting to users and the whole user interface experience, so I suppose it will be an interesting read.
Usage
Plugin is really simple to use:
$("#ElementToScrollIntoView").scrollintoview();
Plugin automatically finds nearest scrollable ancestor and scrolls it accordingly (if at all needed). There are some additional settings to this plugin you can use and this is how they look like:
scrollintoview: function (options) {
/// <summary>Scrolls the first element in the set into view by scrolling its closest scrollable parent.</summary>
/// <param name="options" type="Object">Additional options that can configure scrolling:
/// duration (default: "fast") - jQuery animation speed (can be a duration string or number of milliseconds)
/// direction (default: "both") - select possible scrollings ("vertical" or "y", "horizontal" or "x", "both")
/// complete (default: none) - a function to call when scrolling completes (called in context of the DOM element being scrolled)
/// </param>
/// <return type="jQuery">Returns the same jQuery set that this function was run on.</return>
I'm using this plugin on my Sharepoint 2010 site on pages where I present long tabular data. Whenever I add a new item (row) to this table I additionally scroll to this new record and highlight it, so users can see the new record immediately.
Sharepoint was also the reason why I decided not to provide scrollable element manually but rather look for it programatically. Sharepoint uses admin costumizable master pages which means I don't know which element is going to be scrollable at runtime. But I do know which element I want to see. Hence this plugin. It's also rather simplified compared to scrollTo()
plugin that supports various different scenarios. Most of the time developers tend to use only one (or a very limited number of them).
Additional observations
Default link click processing prevention
Using my plugins still makes it rather problematic, since there's some flickering when adding those reply boxes. The problem is that your link clicking actually executes. You should prevent this in order to make your page to work smooth:
either set click events on your links in one of these two ways:
<a href="javascript:void AddReplyForm(44); return false;">Reply</a>
or
<a href="#" onclick="void AddReplyForm(44); return false;">Reply</a>
a better way would be to run this on document ready:
$(function() { $("a").click(function(evt) { evt.preventDefault(); }); });
The main idea is to prevent browser from processing link clicks. Because this makes the browser to look for in-page anchor and since it can't find one, it auto scrolls to the top. Then you tell it to scroll to your element.
Duplicate IDs
When you create reply form, you add new and new and new elements but they're all with the same ID. You should either avoid doing this or use some other means. You could remove the need for IDs altogether by providing the element to your BindClick()
function. The main reply generating function could as well look like this (this function is written in a way that completely eliminates the need for element IDs):
function AddReplyForm(topCommentID)
{
var el = $(addReplyForm).appendTo('#comment_' + topCommentID + ' .right');
BindClick(el); // mind this !! you provide the element to remove
el.scrollintoview();
}
Had the same problem... after reviewing a few answers, here's what I came up with for doing this... without pulling down another plugin.
function scrollIntoViewIfNeeded($target) {
if ($target.position()) {
if ($target.position().top < jQuery(window).scrollTop()){
//scroll up
$('html,body').animate({scrollTop: $target.position().top});
}
else if ($target.position().top + $target.height() >
$(window).scrollTop() + (
window.innerHeight || document.documentElement.clientHeight
)) {
//scroll down
$('html,body').animate({scrollTop: $target.position().top -
(window.innerHeight || document.documentElement.clientHeight)
+ $target.height() + 15}
);
}
}
}
The "15" on the last line is just extra padding - you might need to adjust it, or add it to the scroll up line.
EDIT: changed window.innerHeight
to (window.innerHeight || document.documentElement.clientHeight)
for IE < 8 support
All modern Browsers support this. Visit: http://caniuse.com/#search=scrollIntoView
function scrollIntoViewIfNeeded(target) {
if (target.getBoundingClientRect().bottom > window.innerHeight) {
target.scrollIntoView(false);
}
if (target.getBoundingClientRect().top < 0) {
target.scrollIntoView();
}
}
Update
The target has to be an Element. If you use jQuery call the function like this:
scrollIntoViewIfNeeded($(".target")[0]);