简体   繁体   中英

Improving Performance on Background Parallax Scrolling

Hello StackOverflow Community,

what I am trying to achieve is a header that can be moved with the mouse. You klick into the header and drag the mouse and the elements inside the header will move with different speeds.

I achieved the parallaxing part but the performance is not really good. It is partially a bit laggy while dragging the backgrounds.

My question now is: what can be changed in the code to get a performance boost?

That's the part of the code that takes care of parallaxing. On every mousemove a each loop is executed which I think is the reason for the performance beeing so laggy:

var dragging = false;
var clickMouseX;

//Our object for the layers
//each layer has a different scrolling speed
var movingObjects = {
    '#header-l1' : {'speed': 1},
    '#header-l2' : {'speed': 1.4},
    '#header-l3' : {'speed': 1.85},
    '#header-l4' : {'speed': 2.2},
};

$('#header-wrapper').mousedown(function(e){
    dragging = true;

    //Get initial mouse position when clicked
    clickMouseX = e.pageX;

        $(this).mousemove(function(mme){
            //execute only if mousedown
            if(dragging){
                //iterate through all layers which have to be parallaxed
                $.each(movingObjects, function(el, opt){
                    var element = $(el);
                    //get difference of initial mouse position and current mouse position
                    var diff = clickMouseX - mme.pageX;
                    //scroll-position left speed 1
                    if(diff < 0) diff = -1;
                    //scroll position right speed 1
                    if(diff >= 0) diff = 1;
                    //get current position of layer
                    currLeft = parseInt(element.css('left'));
                    //get current layer width
                    elWidth = element.width();

                    //if right border is reached don't scroll further
                    if(currLeft < -(elWidth - 810)){
                        element.css('left', -(elWidth - 810));
                    }           
                    //so do with left border
                    if(currLeft > 0){
                        element.css('left', 0);
                    }
                    //parallax it! Subtract the scroll position speed multiplied by the speed of the desired
                    //layer from the current left property
                    element.css('left', parseInt(element.css('left')) - diff*opt.speed);    
                });
            }
        });


    /* Cursor */
    $(this).css('cursor', 'pointer');
    return false;
});

I also put a fiddle up: http://jsfiddle.net/yWGDz/

Thanks in advance, Thomas

PS maybe someone even finds out why layer two and three have the same scroll speed while having different speeds defined.

I worked at this a bit, and came up with this: http://jsfiddle.net/amqER/2/

This works a lot faster than the original (especially in firefox, where it performs a whole lot better, chrome it's still pretty slow). I also changed up some of the logic in your code, to make it make more sense.

A list of things that I did:

Minify your pngs

2 of your png files were over 2 megs, so I threw them into a png compressor ( tinypng ) and that reduced the size a lot. This helps with loading time and overall snappiness.

Re-use values as much as possible

In your original code, you wrote to and then subsequently read from the css left property a couple times in your code. Doing this is going to make it a lot slower. Instead, I kept an left property, and would only touch $.css when I absolutely needed to. Likewise for reading each element's width each update.

Also, like I said, I modified your logic to (I think) make more sense, given what you were trying to accomplish. It calculates a new diff each update, and tries to move according to that. Also, it doesn't try to keep moving once one of the images falls off (which yours does if you move all the way to the right, and it looks really weird). You can also look at this: http://jsfiddle.net/amqER/5/ , which maybe is more like the control scheme you wanted.

Just some quick performance tips.

Try not to use $(this).mousemove instead save $(this) into a variable and use that.

var th = $(this);
th.mousemove...

Try to avoid using $.each. This is probably the part that's slowing your code down. You can replace it with a for loop, but I would suggest, in this case, sending in each element one by one.

var parallax = function(img){

};

parallax(img1);
parallax(img2);

instantly-increase-your-jquery-performance

Whilst Xymostech's answer does greatly improve upon the original poster's original code; the performance is hardly improved for me in Chrome.

Whilst inspecting the page FPS, the solution posted here runs at 15FPS for me on a Retina MacBook Pro.

I made a very simple change to the code, altering it to use translate3d properties instead of left . Now, it runs at 55-60 FPS for me. I'd call that a massive performance boost.

If 'show paint rectangles' are turned on in Chrome, you'll see the previously posted solution is continually painting changes to the dom whilst the parallax is in motion. With the translate3d solution, there's simply zero painting done the whole time the parallax is in motion.

http://jsfiddle.net/LG47e/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM