The section of code that fires if the element is too high works well, assuming the frame element and it's child elements are relatively positioned. If not, it uses the absolute offset and it doesn't work.
As for the section that fires if the element is too low, I assume that when you say "it always tends to scroll just a tiny bit past the target element rather than right up to its end" you are referring to the fact that the element is cut off if the frame is smaller than its offset. Try the following:
// If the frame is less than or equal to the element's height
if( frameHeight <= elem.attr('height') ){
//Scroll to it's offsetBottom - the total frameHeight, so that the full element will be displayed
frame.scrollTop( offsetBottom - frameHeight );
}else {
//Else, the element's height is less than the frame, so the entire element will be displayed if we just scroll to the element's offsetBottom.
frame.scrollTop( offsetBottom );
}
I created an HTML demo page as follows and did not experience any other issues. Play around with the heights of elements and see if you can get it to break. I used Firefox 3.5 and everything was cool.
<button id="buttonTest1">Slide to Test1</button> <button id="buttonTest2">Slide to Test2</button>
<div style="position:relative;width:100%;height:620px;overflow:scroll;">
<div style="position:relative;height:50px;"></div>
<div id="childSlide1" style="width:50px;height:50px;position:relative;">Test</div>
<div id="childSlide2" style="width:50px;height:50px;position:relative;top:850px;">Test2</div>
</div>
$(document).ready(function(){
function keepScrolledOver( elem ){
var frame = elem.parent();
var scrollPos = frame.scrollTop();
var offset = elem.attr( "offsetTop" );
alert ('scrollPos: '+scrollPos+' offset: '+offset);
//var jQoffset = elem.offset();
//alert ('jQoffset: '+jQoffset.top+' '+jQoffset.left);
// If the element is scrolled too high...
if( offset < scrollPos )
{
alert ('scrollPos '+scrollPos+' is bigger than offset '+offset);
frame.scrollTop( offset );
// frame.attr( "scrollTop", offset );
}
// If the element is scrolled too low...
else
{
var frameHeight = frame.height();
var offsetBottom = offset + elem.height();
var scrollBottom = scrollPos + frameHeight;
alert('frameHeight: '+frameHeight+' offsetBottom: '+offsetBottom+' scrollBottom: '+scrollBottom);
if( offsetBottom > scrollBottom )
{
// frame.attr( "scrollTop", offsetBottom );
if( frameHeight <= elem.attr('height') )
{
frame.scrollTop( offsetBottom - frameHeight );
// frame.attr( "scrollTop", offsetBottom - frameHeight );
}else {
frame.scrollTop( offsetBottom );
}
}
}
}
$('#buttonTest1').click(function(){
var scrollElement = $('#childSlide1');
keepScrolledOver(scrollElement);
});
$('#buttonTest2').click(function(){
var scrollElement = $('#childSlide2');
keepScrolledOver(scrollElement);
});
});