Search code examples
jquerydynamicscrollposition

scrolling to div inside absolute positioned parent div with changing height


Here's my body:

body
{
    height:100%;
    width:100%;
    margin:0;
    padding:0;  
    overflow:hidden;
    overflow-y:hidden;
    -webkit-overflow-scrolling:auto;
   /* aesthetic stuff */
}

Here's the .page div:

.page
{
    position:absolute; 
    top:0; 
    bottom:0;
    left:0; 
    right:0;
    margin-top:60px;
    z-index:1;
    overflow-y:scroll; 
    -webkit-overflow-scrolling:touch;   
    /* aesthetic stuff */
}

Here's the list item div

.item
{
    position:relative;
    height:80px;
    width:100%;
    margin:0;
    padding:0;
    /* aesthetic stuff */
}

Here's some HTML:

<body>
    <div id="pages-1" class="page"></div>
</body>

.page gets filled dynamically with an unspecified number of these:

<div class="item">Unique Item Content</div>

When you click on an .item div, an unspecified number of other .item divs get .hide() called on them, to filter them out. I then scroll the clicked .item to the top of the window, no problem.

But when you click on the selected .item again, to unselect it, all the .item instances that were previously hidden now get .show() called on them, sending the previously selected, now unselected .item to a new position relative to .page and to window.

I don't have an issue scrolling to the top of selected .item when you first select it. But on .item instances that live toward the bottom of the unfiltered set of .item divs, when you unselect it I cannot get it to scroll to the top of that item at all. I can't even get anywhere close. EDIT: When I say I can't get it anywhere close, I mean, it's not even in the viewport by a mile. END EDIT Now on .item instances that are not toward the bottom of the set of divs, scrolling to it upon unselect mostly works. But on an .item toward the bottom, not close.

I've tried using its current ($(el).position()).top after it is unselected, I've tried storing its original position.top in jQuery data when it is first selected, prior to filtering out the other divs. I've tried combinations of things.

I'm starting to think it's a lost cause. Maybe it has to do with .page being absolute positioned, but I can't change that for other reasons.

UPDATE

Further tests:

// $('.item.certain-ones').not(el).hide(); or $('.item').not(el).show(); here
alert($(el).position().top);
$('.page').scrollTop($(el).position().top);
alert($(el).position().top);

Results: - On Select: 140, then 0 - On Deselect: 0, then 1700

So I tried running the scrollTop twice, to see what shakes out:

// $('.item.certain-ones').not(el).hide(); or $('.item').not(el).show(); here   
alert($(el).position().top);
$('.page').scrollTop($(el).position().top);
alert($(el).position().top);
$('.page').scrollTop($(el).position().top);
alert($(el).position().top);

Results:

  1. On Select: 140, then 0, then 140
  2. On Deselect: 1240, then 0, then 1240 (not visible in viewport at end)

But...

If after selecting the .item, I manually scroll UP just a little bit, the item stays exactly where it was in the viewport on deselect:

  1. On Select: 140, then 0, then 140
  2. Scroll up a tad ...
  3. On Deselect: 73, then 1167, then 73 (perfectly in viewport, as if the other elements had not just been shown above and below it; it doesn't even move visibly).

However, if I manually scroll DOWN a tad, the results are the same as if I didn't manually scroll at all (see above, e.g., 1240, then 0, then 1240), i.e., not close to being visible in viewport.


Solution

  • So my various tests, particularly where when I manually scrolled up, it somehow reset the viewport so that $(this).position().top became "recognized." I don't know how to explain it, but I tried this and it solves my problem 100% and scrolls directly to the precise top of the unselected element every single time:

    $('.page').scrollTop(0).scrollTop($(el).position().top);
    

    where el is the clicked .item.

    Works perfectly.