2

I have created a small demo of two boxes animating in and out based on scroll position. But this isn't exactly what I want to achieve. What I want is for the boxes to animate based on scroll position not just transition in and out when a certain point is reached.

For example the scrolling should control the animation so if you scroll down the boxes will animate in, if you scroll up they will animate out. If you stop scrolling mid animation the animation will stop. If you reverse the scroll position the animation will reverse. So the animation only happens as you scroll.

I hope that is clear enough for you to understand. I will try provide a link to what I am trying to achieve. But for now here's my demo just using a transition to animate the boxes.

jQuery(document).ready(function($){
 var scroll_pos = $(window).scrollTop();
    var box = $('#container').offset().top - 200;
    
    $(window).on('scroll', function(){
     scroll_pos = $(window).scrollTop();
        
     $('p').html(scroll_pos);
        
        if(scroll_pos >= box){
         $('#left').addClass('animate');
         $('#right').addClass('animate');
        }else{
         $('#left').removeClass('animate');
         $('#right').removeClass('animate');
        }
    });
   
});
#container{
    width: 600px;
    height: 300px;
    margin: 1000px auto;
    overflow: hidden;
    font-size: 0;
}

#left{
    width: 55%;
    height: 300px;
    background-color: blue;
    display: inline-block;
    transform: translateX(-100%);
    transition: all 0.5s; 
}

#right{
    width: 45%;
    height: 300px;
    background-color: yellow;
    display: inline-block;
    transform: translateX(100%);
    transition: all 0.5s; 
}

#left.animate{
    transform: translateX(0%);
}

#right.animate{
    transform: translateX(0%);
}

p{
    position: fixed;
    top: 0;
    left: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<p></p>

<div id="container">
    <div id="left"></div>
    <div id="right"></div>
</div>

Here's an example of what I want to achieve. As you can see the scroll controls the animation of the fidget spinner https://ampbyexample.com/visual_effects/basics_of_scrollbound_effects/

Reece
  • 2,581
  • 10
  • 42
  • 90
  • Being able to control/cancel animations while they happen is the main reason behind [Web Animations API](https://drafts.csswg.org/web-animations/). Although it started almost a decade ago, it's still in draft and far from having decent browser support. Your only other option is to use [velocity.js](http://velocityjs.org/) and transition to => *maths here, based on scrollPosition*. To be exact, instead of using classes (`.animate`) to apply transforms, you use velocity.js to apply an animated transition to a new custom value of `translateX`, based on scrollPosition – tao Aug 02 '18 at 11:12
  • Even though `velocity.js` is pretty much the best you can currently hope for on the job, it's still going to be jerky on mobiles, as they don't trigger `scroll` as often, for the sake of "user experience". Some devices don't `scroll` at all, you'll need to dive into touch events (which is a can of worms :D) – tao Aug 02 '18 at 11:16

1 Answers1

1

Based on this answer you could do someting like:

/**
 * inViewport jQuery plugin by Roko C.B.
 * http://stackoverflow.com/a/26831113/383904
 * Returns a callback function with an argument holding
 * the current amount of px an element is visible in viewport
 * (The min returned value is 0 (element outside of viewport)
 */
;(function($, win) {
  $.fn.inViewport = function(cb) {
     return this.each(function(i,el) {
       function visPx(){
         var elH = $(el).outerHeight(),
             H = $(win).height(),
             r = el.getBoundingClientRect(), t=r.top, b=r.bottom;
         return cb.call(el, Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H)));  
       }
       visPx();
       $(win).on("resize scroll", visPx);
     });
  };
}(jQuery, window));


// Now our stuff:

var $container = $("#container");
var $left = $("#left");
var $right = $("#right");

$container.inViewport(function( px ) {
  var v = 1 - px / $container.height(); // Value from 1.0 to 0.0 and v.versa
  $("p").text(v);
  $left.css({transform: `translateX(${ -v * 100 }%)`});
  $right.css({transform: `translateX(${ v * 100 }%)`});
});
body {
  height: 500vh;
}

#container {
  position: relative;
  margin: 0 auto;
  top: 200vh;
  overflow: hidden;
  width: 60vw;
  height: 60vh;
}

#left,
#right {
  width: 50%;
  height: 100%;
  float: left;
}

#left {
  background-color: blue;
  transform: translateX(-100%);
}

#right {
  background-color: yellow;
  transform: translateX(100%);
}

p {position: fixed; top:0; left: 0;}
<div id="container">
  <div id="left"></div>
  <div id="right"></div>
</div>

<p></p>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313