Dynamic parallax effect with scroll wheel on WebKit

Currently experiencing some challenges with parallaxing backgrounds. I developed a website for an event organized by my friends, featuring multiple background images that shift between content sections to create a parallax effect. I have implemented code to adjust these background images while scrolling, yet there seems to be a delay in the parallax effect specifically in WebKit browsers when using the scrollwheel.

You can view the website here:

I aimed to replicate the parallax effect seen on the Spotify website as inspiration:

Although my implementation mirrors the approach taken by Spotify - utilizing a throttled function to calculate background transformations based on vertical scroll position - there is noticeable lag compared to their seamless transition. The functionality works smoothly in Firefox/IE and even in WebKit browsers when manually sliding the scrollbar, but the visual delay persists.

If anyone has insights on how to address this latency issue, your tips would be greatly appreciated.

Below is the code snippet for the parallax functionality (apologies for the excessive use of this due to Prototype):

    parallaxBackground: function () {
        var viewportTop = this.elements.$document.scrollTop();
        var viewportBottom = viewportTop + this.elements.$window.height();
        var scrollDelta = this.slideHeight + this.elements.$window.height();

        $.each( this.backgroundSlides, function ( index, slide ) {
            var slideTop = slide.$container.offset().top;
            var slideBottom = slideTop + this.slideHeight;
            if ( slideBottom < viewportTop || slideTop > viewportBottom )
                return true;
            var factor = 1 - ( slideBottom - viewportTop ) / scrollDelta;
            this.transformBackground( slide.$image, this.slideLength * ( factor - 1 ) );
        }.bind( this ) );
    },

    transformBackground: Modernizr.csstransforms ? function ( $backgroundElement, distance ) {
        $backgroundElement.css( {
            '-ms-transform': 'translate(0px, ' + distance + 'px)',
            '-webkit-transform': 'translate(0px, ' + distance + 'px)',
            'transform': 'translate(0px, ' + distance + 'px)'
        } );
    } : function ( $backgroundElement, distance ) {
        $backgroundElement.css( 'top', distance );
    }

Here's how it is linked (employing Underscore for throttling):

this.elements.$window.on( 'scroll',
    _.throttle( this.parallaxBackground.bind( this ), 16 ) );

Answer №1

After creating my own version of the parallax effect inspired by Spotify's website, I encountered many of the challenges discussed in this post.

Although I couldn't completely eliminate the stutter on Safari, I was able to achieve a smooth 60fps performance on Chrome and Firefox.

I've shared it as a jQuery plugin on this link, but feel free to adjust it to suit your preferred framework:

Implementing several optimization tips greatly improved the performance:

  1. Avoid triggering layout changes unnecessarily

  2. Minimize logic attached to scroll events, consider using setTimeout or requestAnimationFrame instead

  3. Opt for position:fixed; on background elements to minimize lag on certain browsers

  4. Improve browser layering with null transforms, but use them judiciously

  5. Use Chrome DevTools for diagnosing performance bottlenecks

Following these guidelines significantly reduced the stutter in my implementation.

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

Incorporating external CSS links in the metadata of Next.js 13

A recent update in Nextjs 13 introduced a new feature known as Metadata (https://nextjs.org/docs/app/api-reference/functions/generate-metadata), causing the removal of Head.js. Previously, I would import a CSS file using the <Head> tag as shown below ...

What is the best way to integrate nano.uuid into a series of promises that are fetching data from the database?

When working with express routing and nano, I encountered a challenge: router.get('/', function (request, response) { db.view('designdoc', 'bydate', { 'descending': true }) .then(results => { // data ...

The responseXML received from an Ajax/POST request is missing only when using Chrome browser

While working on a "simple" JavaScript application, I noticed an unusual behavior. A function in the script sends a request with parameters to a .php page using the traditional Ajax/POST method. function sendRequest(params, doAsync, onSending, onDone) { v ...

Troubining CSS nth-of-type or child selectors with custom elements within additional custom elements may cause unexpected behavior

Struggling with CSS :nth-child and creating a unique layout with custom elements inside custom elements. The issue arises when trying to display different icons using the :before pseudo-element, but all icons end up being the same. Below is the code snippe ...

Enhance user interactivity by incorporating dynamic checkboxes, radio buttons, checkbox groups, and radio button groups using Ext

Hello to all the amazing folks at Stack Overflow! I've tried searching for a solution to this issue on Stack Overflow, but I couldn't find anything helpful. Here is my model: Ext.define('soru', { extend: 'Ext.data.Model' ...

Styling with CSS to accentuate the currently active tabs

Struggling with writing CSS to meet the following requirements after creating a tab and calling a function on click: 1. The active tab should display a blue underline color. 2. When clicking on a tab, the blue line should appear under the active tab (sim ...

Utilize range slider to refine dataset

I have implemented a jquery datatable along with the range.slider plugin. My goal is to apply the range slider to filter out data in the last column. In my attempt, I am using search.push to accomplish this filtering process. Below is an example of my i ...

Toggle sidebar visibility with a button click

Currently, I am working on a sidebar that can collapse and expand when a button is clicked. If you wish to take a look, I have created a JSFiddle for reference: https://jsfiddle.net/4er26xwp/1/ The challenge I am facing lies here: document.getElementsByC ...

Mastering the art of simultaneously running multiple animations

Utilizing two functions to apply a Fade In/Fade Out effect on an element. Confident in the functionality of both functions, as testing them sequentially in the Console proves their effectiveness. However, executing: fadeIn() fadeOut() seems to result in ...

Mocha Chai: Dive into an array of elements, discovering only fragments of the desired object

Currently, I am utilizing the assert syntax of chai. I have a dilemma regarding checking an array of objects for a specific object. For example: assert.deepInclude( [ { name: 'foo', id: 1 }, { name: 'bar', id: 2 } ], { n ...

Run a function continuously while a key is being held down

I am currently working on a Javascript program that will move a div up and down based on key inputs. The idea is to continuously update the 'top' style value of the div while a specific key is pressed. While the basic function works, I am struggl ...

In JavaScript, create a function that returns an object instead of an array when using

In the code snippet below, I am trying to work with file names: var completename = file.name; var regex = '/-\w+_/'; var filenameTest_components = completename.match(/-\w+_/); console.log(completename); console.log(typeof filenameTest_ ...

After making a POST request, I must ensure that the page is rendered accordingly

How can I efficiently handle requests to the server and update the page without reloading it, following SPA principles using useEffect()? I attempted to implement something like this: useEffect (() => { addProduct (); }) but it proved to be ineffectiv ...

where is the yarn global registry located?

After updating yarn to point to my custom registry and verifying the changes, here is what I found: $yarn config list -g yarn config v1.22.10 info yarn config { 'version-tag-prefix': 'v', 'version-git-tag': true, ' ...

Ways to modify text at regular intervals

I've come across some code that utilizes an array of text to update the content inside a span: var texts = ["Hola", "Bonjour", "Hallo"]; var count = 0; function changeText() { $("#example").text(texts[count]); count < 3 ? count++ : count = ...

The form reset function came back as null in the results

I'm attempting to reset the form inputs with the following code: $("#form_employee_job")[0].reset(); Even after executing the code, the inputs remain filled and the console shows undefined What am I overlooking? https://i.sstatic.net/sqzzZ.jpg ...

Tips for adjusting the font size of a Chip using Material-UI

I am using a widget called Chip const styles = { root:{ }, chip:{ margin: "2px", padding: "2px" } } const SmartTagChip = (props) =>{ const classes = useStyles(); return( <Chip style={{color:"white&q ...

Rails 4 experiences a strange phenomenon where Ajax is triggered twice, resulting in the replacement of

After reviewing other similar questions, it appears that the best approach is to wait for the initial Ajax request to complete before proceeding with the next one. I believed that the following code would handle this situation, but somehow the request is t ...

Is it possible to modify the color of a division row using an onchange event in JQuery?

I am facing a requirement to dynamically change the color of rows based on the dropdown onchange value. The rows are structured in divisions, which were previously tables. There are two main divisions with rows that need to be updated based on dropdown sel ...

After implementing ajax, jQuery ceases to function

I have been working with multiple JavaScript files and everything is functioning perfectly (including functions that add styles to elements), but I am encountering an issue when trying to include the following script: <script src="http://ajax.googleapi ...