Is it better to use a canvas for a more efficient animation when changing the background image on pagescroll?

I'm currently working on a parallax website that consists of a sequence of around 400 images. The background images change dynamically as the user scrolls through the page, creating a smooth animation effect. While I have managed to implement the scrolling functionality, I am encountering issues with the transition between background images not being seamless. There is a brief moment where a blank space is visible, depending on the internet connection speed. Additionally, the images are not being cached, leading to a new image request every time. I'm seeking advice on how to optimize the code to ensure smooth animation transitions without requesting new images each time and utilizing cached images effectively. I also explored using canvas for the animation, but encountered similar issues with image requests upon scrolling. Here is my current code structure for standard background image changing based on page scroll:

HTML

<div class="container">
    <div id="background-images" class="background-images">
        <div class="test"></div>
    </div>
</div>

CSS

#background-images{
    height: 4000px;
}
.container{
    border: 1px solid red;
    height: 400px;
    overflow: auto;
}
.test{
    position: fixed;
    top: 0;
    left: 0;
    z-index: 999;
    width: 600px;
    height: 600px;
}

Javascript

var $container = $(".container");
var $bgImage = $(".test");

// Attaching the scroll event to the background image
$container.scroll(function(event) {
    var position = $container.scrollTop();
    setBgImage(position);
});

// Preload the specified number of images for caching
function preload(totalImages) {
    for (var i = 0; i < totalImages; i++) {
        $('<img/>')[0].src = getImgUrl(i);
    }
}
preload(36); // Preload 36 images to be cached

// Set the background image based on scroll position
function setBgImage(position){
    var imageNum;
    var lineCount = 0;

    imageNum = parseInt(position  / 100);

    console.log("IMG: " + imageNum + ", Position: " + position);
    $bgImage.css("background-image", "url('" + getImgUrl(imageNum) + "')");
}

// Get the URL for the placeholder background image
function getImgUrl(num){
    return "http://placehold.it/200x200/&text=" + num;  
}

JSFiddle: http://jsfiddle.net/4j9u8qtf/1/

Answer №1

To display only the correct image and hide the rest, consider adding all images to the DOM but showing only the desired one using an actual image element instead of a CSS background image. I have made changes to your jsfiddle to illustrate this technique:

function create(totalImages) {
    for (var i = 0; i < totalImages; i++) {
        var img = $('<img/>');
        img[0].src = getImgUrl(i);
        $bgImage.append(img);
    }
    setBgImage(0);
}

create(37);

function setBgImage(position){
    var imageNum;
    var lineCount = 0;

    imageNum = parseInt(position / 100);

    console.log("IMG: " + imageNum + ", Position: " + position);

    $bgImage.find("img").hide().eq(imageNum).show();
}

http://jsfiddle.net/y92g7vvL/1/

Answer №2

If you want to efficiently preload images, the best method is to utilize the Image constructor as shown in the example below. By using the Image constructor, there is no need to worry about attaching the images to the document for them to load.

function preload(url) {
  var image = new Image();
  image.src = url;
}

I have made changes to your Fiddle to incorporate this preload technique and eliminate the use of jQuery for setting the background-image. The result is that all images are now preloaded and loaded only once with improved performance.

$(function () {
    var $container = $(".container");
    var $bgImage = $(".test");
    var bgImage = $bgImage.get(0);

    $container.scroll(function (event) {
        var position = $container.scrollTop();
        setBgImage(position);
    });

    // preload the specified total number of images
    function preload(totalImages) {
        function fetch(url) {
          var image = new Image();
          image.src = url;
        }

        for (var i = 0; i < totalImages; i++) {
            fetch(getImgUrl(i));
        }
    }

    preload(36);

    function setBgImage(position) {
        var imageNum;
        var lineCount = 0;

        imageNum = parseInt(position / 100);
        var url = getImgUrl(imageNum);

        bgImage.style.backgroundImage = "url('"+ url +"')";
    }


    function getImgUrl(num) {
        return "http://placehold.it/200x200/&text=" + num;
    }
})

Answer №3

Experiment

coding tutorials

<div class="container">
    <div id="background-images" class="background-images">
        <div class="test"></div>
    </div>
</div>
<!-- hidden container for `img` elements -->
<div id="imgs"></div>

styling

#imgs {
  display:none;
}

javascript

$(function () {
    var $container = $(".container");
    var $bgImage = $(".test");

    $container.scroll(function (event) {
        var position = $container.scrollTop();
        setBgImage(position);
    });

    // preload a total number of images for optimization
    function preload(totalImages) {
        for (var i = 0; i < totalImages; i++) {
            $('<img/>', {
                "src": getImgUrl(i)
            })
            // append `img` elements to `#imgs` container
            // for image caching, 
            // preventing unnecessary requests
            .appendTo("#imgs");

        }
    }

    preload(36);

    function setBgImage(position) {
        var imageNum;
        var lineCount = 0;

        imageNum = parseInt(position / 100);

        console.log("IMG: " + imageNum + "
                   , Position: " + position
                   , $("#imgs img[src$=" + imageNum + "]"));

        // use existing cached images in DOM  
        // set background-image of `$bgImage`
        // from hidden `#imgs` `div`
        // images are not re-requested
        // on background-image adjustments
        $bgImage.css("background-image"
        , "url('" + $("#imgs img[src$=" + imageNum + "]").attr("src") + "')");
    }


    function getImgUrl(num) {
        return "http://placehold.it/200x200/&text=" + num;
    }
});

play around with the code http://jsfiddle.net/guest271314/bh91g0tv/

Answer №4

The repeated requests are due to the use of jQuery for setting background images, causing them to reload each time.

It may seem unnecessary to rely on jQuery in this scenario, as it can lead to unintended side effects that exacerbate your issue.

Simplify by directly configuring the X position of the background instead.

function offset_to(id, posX, posY) {
    document.getElementById(id).style.backgroundPosition = posX.toString() + 'px ' + posY.toString() + 'px';
}

Answer №5

To give your image transition a smooth appearance, apply the following CSS transition properties:

.test{
    -webkit-transition: all 0.5s ease;
    -moz-transition: position 10s;
    -ms-transition: position 10s;
    -o-transition: position 10s;
    transition: all 0.8s ease;
}

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

What is the best way to achieve a perfect rounded div using Bootstrap 4?

While browsing through the Bootstrap documentation and searching on stackoverflow, I came across a solution to create circular images using border-radius set at 50%. However, when I tried implementing it with my slightly oversized image, it ended up lookin ...

Understanding the concept of closures in JavaScript is crucial for effective programming

The snippet of code shown below continuously outputs the number 10. How can I modify it to display the sequence: 0 1 2 3 4 5 6 7 8 9 Below is the code in question: function go() { var procedures = []; for (var i = 0; i < 10; i++) { pro ...

Designing a navigation system that revolves around a central logo image

I have created a navigation bar that you can see in this image: https://i.stack.imgur.com/eT4TL.jpg Using foundation to construct a website, I have designed the nav bar in the following manner: HTML: <nav class="top-bar"> <ul> ...

What is the best way to center text in a div with a distinct background color?

Could really use some assistance with this. Here are the images for reference: https://i.stack.imgur.com/JNZkT.jpg Currently getting this result: https://i.stack.imgur.com/nW17o.jpg <style> .Nav_bar_links div{ margin: 0% 1 ...

What is the best way to ensure that my transitionend event is triggered?

I'm currently exploring the <progress> element and attempting to incorporate a CSS transition to achieve a smooth progress bar effect as its value increases. Despite my efforts, I can't seem to trigger JS after the transitionend event occur ...

Ensure that the video is properly positioned within the background when utilizing the background-size cover property

I am currently working on a project that requires me to position a video clip on a specific section of the background image, ensuring that the video always appears on top of the phone's screen. The responsive background image is constantly changing. H ...

Modify just one of the padding axis while keeping the other constant by utilizing a media query

My div currently has the following padding set: padding: 14px 150px; I want to change the left/right padding without affecting the top/bottom padding using a media query. @media screen and (max-width: 700px){ #paddingDiv{ padding: same as ...

One method of dirty checking using a shared service among controllers is effective, while the other method is not successful

As I was trying to solve the problem of sharing data between two separate controllers, I encountered a curious issue. Usually, I rely on services for this task and started creating a jsfiddle example, but unfortunately, I couldn't get it to function ...

Accessing Rails instance variables in an AJAX request and iterating over them

I am currently working on a Task Management System which includes the integration of fullcalendar.js. My goal is to identify pending tasks and change their color for better organization. I have successfully retrieved the instance variable containing the de ...

Why was the express.js boilerplate code created?

As a newcomer to Node and Express, I am curious about the purpose of the boilerplate directories that are automatically generated when setting up an express project. I have searched online for explanations on the significance of these files without much l ...

JavaScript API for Facebook

I've been attempting to retrieve my status from Facebook using the JavaScript API. Below is the code I have been using: <div id="fb-root"></div> <div id="data"></div> <script src="http://connect.facebook.net/en_US/all.j ...

What is the method for adding content to the initial frame?

Here is the code snippet that I am currently working with: <frameset rows="70,*" frameborder="0" border="0" noresize=""> <frame name="heading" scrolling="no" noresize="" src="head.htm" marginwidth="0" marginheight="0"> <frame name="onli ...

Deciphering the Results of AngularJS

What sets 'template' apart from 'templateUrl' in AngularJS directive? index.html: <!DOCTYPE html> <html lang="en" ng-app="app"> <head> <meta charset="utf-8"> <title>Index</title> </he ...

Sending the axios fetched property from the parent component to the child component results in the error message "TypeError: Cannot read property 'x' of undefined"

I've noticed that this question has been asked before, but none of the solutions provided seem to work for my situation. Parent component import axios from "axios"; import { useEffect, useState } from "react"; import Child from &q ...

Can anyone provide guidance on activating bootstrap tabs-left in bootstrap 3.3.x?

I've noticed that the style nav-tabs left isn't functioning in Bootstrap versions 3.3.0 and 3.3.2. I'm curious if anyone has found a way to re-enable this style so that tabs can run vertically with content displayed on the right. For those ...

Adjust the image to stretch and crop appropriately to perfectly fit the specified dimensions

I have a div with an image inside of it, and the overflow of the div is set to hidden so that the image will be cropped if it exceeds the width or height. It was working correctly, but sometimes it doesn't. What could be causing this issue? Here is th ...

Error: The locator I used with the ID getUserById did not find any elements

Here is the code snippet from my HTML file: <h1>User list</h1> <button class="btn btn-primary" [routerLink]="'/register'">Register</button> <br> <br> <table class="table& ...

Simulate internationalization for vue using jest

Currently, I am working on setting up jest unit tests for a Vue project within a complex custom monorepo. I am facing an issue with i18n, which I use for translation management in my application. The problem arises with the following code snippet for init ...

Refreshing select2 dropdown options dynamically with AJAX updates

I have a select dropdown for locations that is initialized using select2 on page load. I am looking to dynamically update the data in the dropdown at regular intervals using ajax calls. However, when I attempt to update the data in select2, the dropdown ...

What is the process for altering an SVG image following a click event in Javascript?

I have a tab within a div that includes text and an svg icon as shown herehttps://i.stack.imgur.com/TjwIK.png When I click on the tab, it expands like this https://i.stack.imgur.com/XNuBi.png After expanding, I want the svg icon to change to something e ...