Lenny
Lenny

Reputation: 456

Is it possible to CSS scale transition without flickering between states on scroll?

I'm trying to create an effect where a div in a list within a certain area of the page will become larger, without flickering upon crossing the transition point (prominent problem in Chrome, maybe other browsers as well).

Here's a jsfiddle of my current situation.

I've pretty much accomplished what I need, thanks to a great jsfiddle contribution here on Stackoverflow – but when I add my own scale effect it kind of flickers if you scroll too slow over the transition border. This is obviously because the scale transition (or normal height/width change) causes the shrink back inside the border once it has already passed the transition point, and vice versa of course.

Is there a method of making this work with a CSS method, or do I need to alter the script – and in that case (since I'm not that familiar with this kind of math equations) how?

$(document).ready(function () {
    $(window).on('scroll', function () {
        var windowHeight = $(window).height(),
            gridTop = windowHeight * .3,
            gridBottom = windowHeight * .6;
        $('ul li').each(function () {
            var thisTop = $(this).offset().top - $(window).scrollTop();

            if (thisTop > gridTop && (thisTop + $(this).height()) < gridBottom) {
               // $(this).css('background', 'red');
                                    $(this).addClass('in_zone');
                            } else {
                //$(this).css('background', 'silver');
                                    $(this).removeClass('in_zone');
            }
        });
    });
    $(window).trigger('scroll');
}); 

Upvotes: 2

Views: 247

Answers (1)

Rory McCrossan
Rory McCrossan

Reputation: 337580

The issue is due to your check of the bottom of the element being outside the bottom of the area. When the element is enlarged, the next time scroll fires it will revert back to the smaller state as the bottom of the element is outside the area. Then next scroll it will be made large again as the smaller element is now wholly inside the area, and so on.

To fix this you would need to only base the check on the top of the element being within the area, like this:

if (thisTop > gridTop && thisTop < gridBottom) {
    $(this).addClass('in_zone');
} else {
    $(this).removeClass('in_zone');
}

// Note that you can also re-write this logic with a single call to `toggleClass()`:
$(this).toggleClass('in_zone', thisTop > gridTop && thisTop < gridBottom);

You would also need to ensure that the CSS scaling origin point is at the top of the element, so that the top position is a static value. You can do that using transform-origin (and it's vendor prefix equivalents):

transform-origin: 50% 0%;

Working example

Or alternatively, you would need to make the 'large' state smaller, or the hit area taller, but that would suffer from the same issue when the elements are near the boundaries of the detection area.

Upvotes: 4

Related Questions