Animating visuals with scrolling

I came across a useful example on this demo page (http://jsfiddle.net/MMZ2h/4/) that shows how to move an image when scrolling, but I noticed that if you scroll up and down repeatedly, the image eventually goes out of bounds. Why does this happen and what can be done to fix it?

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 №1

Your code isn't functioning as expected because each time the scroll event is triggered, the image position animation occurs. However, this animation takes 10 milliseconds to complete, and because you specify an increment or decrement based on the current position, the position will be calculated wrongly and eventually break.

Here's a revised version of the code:

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

var scrollHeight = $('#div2').prop('scrollHeight') - $('#div2').innerHeight(); // obtain the scroll height
var initialMiddleScroll = scrollHeight / 2; // calculate the middle scroll
$("#div2").scrollTop(initialMiddleScroll); // set the scroll to the middle for left and right movement
$("#div2").scroll(function (event) {
  var st = $(this).scrollTop();
$("img").animate({ left: initialImgScrollLeft + (st - initialMiddleScroll) * delta }, 10); // compute the correct position for the image
});
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-----

To elaborate on what goes wrong in your code:

  • You scroll down
  • The final scroll position is computed at 10px (incrementing from 10 to 10)
  • The scroll triggers the animation
  • The animation starts
  • The scroll position moves from 0px to 10px
  • The animation ends
  • You scroll down again, repeating...

This scenario works, but in many cases, you will scroll multiple times during the animation:

  • You scroll down
  • The final scroll position 1 is computed to be 10px
  • The scroll triggers animation 1
  • Animation 1 begins
  • The scroll position moves from 0px to 3px
  • You scroll down again
  • The final scroll position 2 is computed at 13px (3 + 10)
  • Animation 2 begins
  • The scroll position moves from 3px to 10px (the final position of animation 1)
  • Animation 1 ends
  • The scroll position moves from 10px to 13px (the final position of animation 2)
  • Animation 2 ends

After two scroll events, you have 13px as the scroll position instead of the expected 20px.

The solution is not to rely on relative positioning values but on absolute positioning values (based on the div scroll rather than the previous image position).

If you need further clarification, feel free to ask.

PS: I've updated the code snippet to demonstrate how you can handle the left-right animation.

Answer №2

To achieve this effect, utilize the mouse Wheel event and retrieve the delta from the event object.

Here is an example for your reference:

document.getElementsByTagName('div')[0].addEventListener('wheel', 
 function(e) {
  if(e.wheelDelta > 0) {
    $('img').animate({top: '+=3'}, 10);
  } else {
    $('img').animate({top: '-=3'}, 10);
  }
});

Check out the demo here

Experiment with different delta values to customize the behavior.

Answer №3

Feel free to test out this code snippet:

jQuery(window).on('load resize scroll', function() {
  jQuery('.bg-static').each(function() {
    var windowTop = jQuery(window).scrollTop();
    var elementTop = jQuery(this).offset().top;
    var leftPosition = windowTop - elementTop;
      jQuery(this)
        .find('.bg-move')
        .css({ left: leftPosition });
  });
});
body {
  font-size: 1.5em;
  font-family: Arial, Helvetica, sans-serif;
}
.section {
  position: relative;
  max-width: 920px;
  min-height: 75vh;
  padding: 40px;
  margin: auto;
  background-color: #48c9b0;
  color: #ffffff;
}
.section.bg-static {
  background-color: #85c1e9;
  background-image: url(https://webmadewell.com/wp-content/uploads/2018/07/img-blog-background-move-scrolling-bg.png);
  background-size: cover;
  background-position: center;
}
.section .bg-move {
  position: absolute;
  top: 0;
  bottom: 0;
  right: auto;
  width: 100%;
  background-image: url(https://webmadewell.com/wp-content/uploads/2018/07/img-blog-background-move-scrolling-boat.png);
  background-size: cover;
  background-position: center;
}
<div class="section">
  Scroll down to see the effect
</div>
<div class="section bg-static">
  <div class="bg-move"></div>
</div>
<div class="section">
  The boat image is moving only when scrolling.
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The YouTube video cannot be embedded in a frame due to its "X-Frame-Options" being set to "SAMEORIGIN"

I'm attempting to populate my Django webpage with content sourced from elsewhere. Within the feed, I have YouTube videos with URLs like: https://www.youtube.com/watch?v=A6XUVjK9W4o However, when I include this on my page, the video doesn't appe ...

The CSS file is not displaying the background image on the PHP file

I am facing an issue with using CSS to include a background image for the layer, but it doesn't seem to be working correctly... The CSS code snippet is as follows: header { background-image: url("boisko.jpg"); background-repeat: no-repeat; background ...

Error: Unforeseen token encountered while attempting to import React in Javascript

Upon executing the command 'npm run start', I encountered this error: import React from 'react'; ^^^^^ SyntaxError: Unexpected identifier at Module._compile (internal/modules/cjs/loader.js:721:23) at Object.Module._exten ...

Displaying text at the 5-second mark and hiding it at the 10-second mark of a video

Is there a way to display text at 5 seconds into a video playing on the website, and then hide it after 10 seconds? $(document).ready(function() { $('video').on('timeupdate', function() { var timeElapsed = Math.round($(this).get( ...

bridging information from tables with text fields in forms

I am working on an HTML/CSS page that utilizes a table layout filled with buttons to mimic a T9 keypad design. Within the page, I have a form containing two text fields. My aim is to populate these text fields with numbers based on the values from the tab ...

Custom dropdown feature in Vue-tables2

Is there a way to customize the select dropdown style in vue-tables2 table? I am trying to change the entire template of the dropdown, not just add CSS classes. My custom template includes additional elements like span and div tags that need to be incorpor ...

When the clear link is clicked, my intention is to utilize the splice function in javascript to remove the entire list

In my angular JS and HTML code, I have a grocery list with a remove link next to each item. Additionally, there is a clear list link that should clear the entire list when clicked. However, when I click on the clear list link, it only deletes one item at ...

The height of the division is either inadequate or excessive when set at 100%

After making progress, I hit a roadblock that has me stumped. The issue I'm facing is with the wrapper height setting. If I set it to auto, it stops at the bottom of the content, leaving the background exposed when the content is shorter than the win ...

Material-UI and TypeScript are having trouble finding a compatible overload for this function call

Currently, I'm in the process of converting a JavaScript component that utilizes Material-ui to TypeScript, and I've encountered an issue. Specifically, when rendering a tile-like image where the component prop was overridden along with an additi ...

How can I activate the fancy box from a specific div element?

There are plenty of variations to this question, but none of them seem to help. I am looking for a way to trigger fancybox from a div. Here is the div in question: <div class="port web">Website</div> This particular div has some CSS styles ap ...

How can I switch between columns in a dual-column layout?

In my latest project, I utilized CSS Flexbox to create a sophisticated two-column layout that allows toggling each column independently. While this functionality is exactly what I need, I can't help but feel that my current method is somewhat cumberso ...

using a variable object to load, access data, and handle errors through mutations

element, I have incorporated two distinct mutations in a single react component: const [get_items, { error, loading, data }] = useMutation(GET_ITEMS); const [add_to_cart] = useMutation(ADD_TO_CART); To streamline and access both components' error, ...

The JavaScript loop is not displaying the correct calculation outcome

$(document).ready(function () { //$('#customer_info #next_step').click(function() { $.getJSON("order/summary_process2.php?jsoncallback=?", function (data) { //iterate over all items in the JSON array for (var x = 0; x & ...

Generating a JavaScript array using concealed data

var a1=$("#orderprogress").val().toFixed(2);//a1=50 var a2=$("#poprogress").val().toFixed(2); //a2=70 If I were to create an array in this format, how should I proceed? graphData = new Array( [a1 value,'#222222'],//[50,'#22222 ...

Angular directive that repeats nested directives should only pass if the parent directive is the last one

I need to trigger an event once all the iterations in this nested loop are completed. While I can use $last to check for the last iteration, I am unable to determine within the inner loop if it is at the $last iteration of the parent loop. Here's what ...

Unable to access the attributes of the mongoose model

I'm experiencing an issue with my mongoose model.find code below Displayed here is my node.js code that utilizes mongoose to interact with MongoDB. However, upon running it, I encounter the following error message: Starting... (node:7863) Unhandl ...

When utilizing Express File Upload, only the initial file is uploaded during a multiple file upload process

Currently, I am developing a function that receives an array of file data obtained from user input on the front end. The files are located within req.files.fileInput, which is an array of file data objects. Within this function, I am iterating through the ...

"Toggling the parent element through jQuery within a search function

I have a similar structure in my table: <input id="mySearch" placeholder="Search..." type="text"/> <table> <th>Main header</th> <tbody id="searchable"> <tr class="parent"><td>Parent</td></tr> ...

Transform the table into a div structure according to the Bootstrap v4 beta guidelines

I'm currently utilizing bootstrap v4 beta and have successfully created a table. Now, I would like to replicate the same table structure using div elements. <div class="container"> <table class="table"> <thead> <tr> ...

How can I manage the asynchronicity of Hapi.js, fs.readFile, fs.writeFile, and childProcess.exec?

My code execution seems to be resulting in an empty list, could it be that my asynchronous calls are incorrect? I've tried rearranging and breaking things into functions but there still seems to be a timing issue with my execution. The order in which ...