R Lacorne
R Lacorne

Reputation: 604

Having difficulty with scrollTop?

So I am building an interface and I have a jQuery on my divs that make them grow in size then makes my wrap div scroll so that the clicked div is displayed on top of the screen.

My problem is that the scrollTop action seems to register the top value of the last div clicked, therefore stoping the scroll halfway there if the top value of the last clicked div was not 0.

Here's my script:

$(".blow").click(function () {

    if ($(this).attr("data-blow") == "false") {
        $(this).animate({
            left: '0px',
            height: '100%',
            opacity: 0.95
        }, 'slow', function () {
            $('#wrap').animate({
                scrollTop: $(this).offset().top
            }, 'slow');
            $(this).removeClass('blow')
            $(this).addClass('overflow')
            $(this).attr("data-blow", "true")
        });
    } else {
        $(this).animate({
            left: '-75%',
            height: '24%',
            opacity: 0.6
        }, 'slow')
        $(this).removeClass('overflow')
        $(this).addClass('blow')
        $(this).attr("data-blow", "false")
    }
});

And here's the link if you want to see how it's behaving at the moment: http://www.rlacorne.com/blow

Thanks for tips on that one!

Upvotes: 1

Views: 603

Answers (1)

Rémi Breton
Rémi Breton

Reputation: 4259

.offset().top returns the number of pixels between the top of the document and the element itself including scrolled pixels. That explains why your elements expand and scrolls correctly if the user hasn't scrolled the page yet, but it doesn't work as expected when you do scroll.

You're gonna have a hard time making animated scrolling like this work with an absolute-positioned wrapper dependent on it's own offset. I suggest dropping the wrapping element altogether. I also suggest animating the width property instead of left, since your animation is sensitive to its position and you actually just want to expand the thing.

Here is my (dumbed down) take on jsfiddle. It is not a copy-paste solution and it will require some tweaking to work as expected.

Considering this following CSS instead of the one provided:

.blow { float:left; clear:left; width:25%; height:25%; overflow:hidden; background-color:hotpink; color:black; }

You can use this JavaScript:

$('.blow').on('click', function(event){
    var element = $(this);
    if(element.attr('data-blow') == 'true'){
        element.animate({ width:'25%', height:'25%' }, 1000).attr('data-blow', 'false')
    } else {
        element.animate({ width:'100%', height:'100%' }, 1000, function(){
            $('body').animate({ scrollTop: element.offset().top });
        }).attr('data-blow', 'true');
    }
});

Differences, explained:

First off, you should cache your $(this) reference as everytime you call it, it traverse the DOM tree to find the element.

var element = $(this);

Secondly, you can chain methods with jQuery. Instead of:

$(this).removeClass('overflow')
$(this).addClass('blow')
$(this).attr("data-blow", "false")

...you can do:

$(this).removeClass('overflow').addClass('blow').attr("data-blow", "false")

Thirdly, this one more of a technicality, but $(element).click(handler) is actually a shortcut for $('element).on('click', handler). I advocate .on() since it leads to a better understanding of events and handlers.

Bonus: hotpink.

Upvotes: 1

Related Questions