Sanjeev Rajasekaran Sanjeev Rajasekaran - 3 years ago 89
HTML Question

Moving Image when scrolled

I learnt from this fiddle( http://jsfiddle.net/MMZ2h/4/ ) how to move the image when scrolled, but if you keep scrolling up and down for a while, the image eventually moves out of bounds. Why is that? and how do we fix that?

var lastScrollTop = 0;
$("div").scroll(function (event) {
var st = $(this).scrollTop();
if (st > lastScrollTop) {
$('img').animate({top: '-=10'}, 5);
} else {
$('img').animate({top: '+=10'}, 5);
}
lastScrollTop = st;
});

Answer Source

Your code doesn't work as expected because each time your scroll event is triggered, your image position animation is performed. But this animation takes 10 milliseconds to end and because you specify an increment or decrement based on the current position, so your position will be computed based on a wrong position and will break after some time.

Try this code

var delta = 2; // specify the delta you want
var initialImgScrollTop = $("img").offset().top; // get the current top position of your image
var initialImgScrollLeft = $("img").offset().left;
$("#div1").scroll(function (event) {
  var st = $(this).scrollTop();
	$("img").animate({ top: initialImgScrollTop - st * delta }, 10); // compute the position your image should be
});

var scrollHeight = $('#div2').prop('scrollHeight') - $('#div2').innerHeight(); // get the scroll height
var initialMiddleScroll = scrollHeight / 2; // compute the middle scroll
$("#div2").scrollTop(initialMiddleScroll); // set the scroll to middle so you can go left and right
$("#div2").scroll(function (event) {
  var st = $(this).scrollTop();
	$("img").animate({ left: initialImgScrollLeft + (st - initialMiddleScroll) * delta }, 10); // compute the position your image should be
});
div {
    width: 150px;
    height:150px;
    overflow: scroll;
    display: inline-block;
}
img {
    position: absolute;
    top:400px;
    left:150px;
    width:50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="div1">This is just some stupid text unworthy of being read, so please don't waste
    <br>your time reading this nonesense.
    <br>Hey! why are you still reading this garbage?
    <br>Stop reading now and start doing something useful, such as getting this leaf to move up
    <br>while you scroll this page.
    <br>On second thought, maybe just continue reading.
    <br>This might be more productive then whatever
    <br>it is you were doing before.</div>
<div id="div2">This is just some stupid text unworthy of being read, so please don't waste
    <br>your time reading this nonesense.
    <br>Hey! why are you still reading this garbage?
    <br>Stop reading now and start doing something useful, such as getting this leaf to move up
    <br>while you scroll this page.
    <br>On second thought, maybe just continue reading.
    <br>This might be more productive then whatever
    <br>it is you were doing before.</div>
<img src="http://sweetclipart.com/multisite/sweetclipart/files/imagecache/middle/nature_seasons_spring_leaf_green.png">

-----UPDATE-----

I will try to explain precisely what breaks in your code. Let's begin with the ideal case when your code works:

  • you scroll down
  • the final scroll position is computed to 10px (you increment from 10 to 10)
  • the scroll triggers the animation
  • the animation begins
  • the scroll position goes from 0px to 10px
  • the animation ends
  • you scroll down again, loop...

Ok this works but in most of cases, you will scroll multiple times during the animation:

  • you scroll down
  • the final scroll position 1 is computed to 10px
  • the scroll triggers the animation 1
  • the animation 1 begins
  • the scroll position goes from 0px to 3px
  • you scroll down again
  • the final scroll position 2 is computed to 13px (3 + 10)
  • the animation 2 begins
  • the scroll position goes 3px to 10px (the final position of your animation 1)
  • the animation 1 ends
  • the scroll position goes from 10px to 13px (the final position of your animation 2)
  • the animation 2 ends

You see that after two scroll events, you have 13px as scroll position while you expect it to be 20px.

My approach is not to depend on the relative value of positioning (based on the previous position of the image what is its new position) but instead to depend on the absolute value (based on the scroll of the div what is the new position of the image).

Hope you understand! If anything unclear, let me know.

PS: I update the code snippet so you can see how you can do for the left-right animation.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download