Keeping the page vertically fixed on an element, when lots of content is revealed above (so causing scroll)

105 Views Asked by At

I have a long page with lots of data tables of hidden content.

They are hidden as they are quite repetitive so not all users want to have to scroll past them all the time.

Frequently down the page there is the option to click to open up all of the hidden data tables.

The problem is, if you go half way down the page and click to open up the tables, all of the content being revealed above the current view causes the page to scroll down, meaning the user becomes disorientated as to where they are on the page.

I've mocked up the problem here. If you scroll down to one of the "show more" links nearer the bottom of the page you'll see what i mean. http://jsfiddle.net/LnubwdzL/

I want the clicked link to remain static under the cursor so that the user knows where they are.

This kind of a solution:

$("a").on('click', function() {
    $('html, body').animate({
        scrollTop: $(this).offset().top
    }, 2000);
});

... from other questions on SO, doesn't seem to cut it. Even if it ends up in the right place the page still moves about a lot before coming to rest.

1

There are 1 best solutions below

9
On BEST ANSWER

If I understand it correctly and as I mentioned in comments, I think you can set the same duration value to both your slideDown(); and your animate() functions, and have them both inside the same click handler.

Your code may then become:

$('a').on('click', function(e){
    e.preventDefault();
    if($('.hide').length>0){$('html, body').animate({scrollTop:$(this).offset().top},400);}
    $('.hide').hide().removeClass('hide').slideDown(400);
});

Hope this helps.

Update #1: Added a check on top of animate() so it does not animate when there is no $('.hide') element present anymore.

Update #2: Take a look at this resulting fiddle of another experiment. Let me know if this was what you were looking for.

The way this works is:

  • Upon click of an anchor, offset().top of clicked element is first stored in a variable named prevOffset.
  • Current $(window).scrollTop() value is also stored in a variable named scrollTop.
  • Then all the .hide elements are temporarily made visible via $('.hide').show();.
  • Another offset().top of the same clicked element is then stored in a variable named currOffset.
  • All the .hide elements are made invisible again via $('.hide').hide();.
  • scrollTop is then animated to a value calculated as: scrollTop+(currOffset-prevOffset).
  • All $('.hide') elements are animated via slideDown().

JavaScript:

var duration=400,hideElements=null,scrollTop=0,prevOffset=0,currOffset=0;
$('a').on('click',function(e){
    e.preventDefault();
    hideElements=$('.hide');
    if(hideElements.length>0){
        scrollTop=$(window).scrollTop();
        prevOffset=$(this).offset().top;
        hideElements.show();
        currOffset=$(this).offset().top;
        hideElements.hide();
        $('html, body').animate({scrollTop:scrollTop+(currOffset-prevOffset)},duration);
        hideElements.removeClass('hide').slideDown(duration);
    }
});

Hope this is what you were looking for.