Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vibrating screen on scroll using transform: scale

I would like a zoom out effect for my header, what loads zoomed in, and on scroll it zoom out.

What I do is to increase the size with transform: scale(1.4) and on scroll I calculate a percentage from the scrollTop and header height and I multiply it with 0.4. The problem is that on scroll the screen starts to vibrate, the scale isn't smooth. Do you have any idea what's wrong with my code or can you tell me what's the best practice to achieve this?

jQuery(document).ready(function(){
    function zoom_out() {
        var page_header_height = jQuery('#page-header-custom').outerHeight();
        var scroll_top = jQuery(window).scrollTop();
        var zoom_multiplier = 0.4;
        var multiplier = (zoom_multiplier*(1-((scroll_top-jQuery('#page-header-custom').offset().top)/page_header_height))) > 1 ? 1 : (zoom_multiplier*(1-((scroll_top-jQuery('#page-header-custom').offset().top)/page_header_height)));

        if(multiplier <= 1) {
            jQuery('#page-header-inner').stop(true, true).transition({ scale: 1/(1+multiplier), translate: '0, -50%'  });

            jQuery('#page-header-custom').stop(true, true).transition({
                scale: 1+multiplier
            });
        }
    }

    zoom_out();

    jQuery(window).on('scroll', function(){
        zoom_out();
    });
});

I created a JSFiddle to see it in action.

like image 737
user1452062 Avatar asked Dec 19 '15 10:12

user1452062


1 Answers

I've updated your Fiddle with smooth scaling using window.requestAnimationFrame. The scale animation is vibrating because you're triggering a translation on each scroll event. Think about it like this:

  1. user scrolls
  2. zoom_out() gets triggered and tells an element to transition it's transform properties. Your element is now transitioning at a certain speed: "length" / transitiontime.
  3. More scroll events have passed and are all triggering zoom_out(). The next transition will probably happen at a different speed, resulting in 'vibrating' animation.

First you can get rid of jQuery's transition() method. If you fire the function at 60fps or close to 60fps it will appear to animate smoothly to the human eye, without the need of transitioning or animating.

if(multiplier <= 1) {
        //jQuery('#page-header-inner').stop(true, true).transition({ scale: 1/(1+multiplier), translate: '0, -50%' });
        //jQuery('#page-header-custom').stop(true, true).transition({ scale: 1+multiplier });
        //becomes:

        jQuery('#page-header-inner').css({ scale: 1/(1+multiplier), translate: '0, -50%' });
        jQuery('#page-header-custom').css({ scale: 1+multiplier });           
    }
}

Getting the function triggered at ~60fps can be achieved in multiple ways:

Throttle your scroll event to 60fps.

Or use window.requestAnimationFrame like in the updated Fiddle

function zoom_out(){
  //calculation code & setting CSS

  window.requestAnimationFrame(zoom_out);
}

//trigger it once instead of the scroll event handler
window.requestAnimationFrame(zoom_out);
like image 161
Luuuud Avatar answered Nov 03 '22 00:11

Luuuud