Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS animation overloads CPU

I have an animation and JS for alternating 2 divs and change their background images (from an array of a few dozens images), sort of interchangeable divs. Everything works just fine, however when the animation runs I can see that my CPU is at 100%. At first I thought it might be due to setInterval, however when I changed the code from alternating the images to just increase a number with each iteration and log it to console - I saw dramatic CPU overload decrease, of about 40-50%. So I understood it might be due to animation.

Here's my HTML code:

<div class="wallpaper wallpaper-1" id="wallpaper-1"></div>
<div class="wallpaper wallpaper-2" id="wallpaper-2"></div>

CSS:

.wallpaper {
    width: 100%;
    height: 100%;
    position: absolute;
    opacity: 0;
    background-repeat: no-repeat;
    background-position: center;
    background-size: cover;
    -webkit-transform: translateZ(0);
    -webkit-animation-timing-function: linear;
}

.animate {
    -webkit-animation-name: fadeInOut;
    -webkit-animation-duration: 6s;
}

@-webkit-keyframes fadeInOut {
    0% {
        opacity: 0;
        -webkit-transform: scale(1);
    }
    16% {
        opacity: 1;
    }
    90% {
        opacity: 1;
    }
    100% {
        opacity: 0;
        -webkit-transform: scale(1.1);
    }
}

And JS that makes it all tick:

Wallpapers.get().then(function(list) {
    var wp1, wp2, divs = [], path, bgs = [], counterBgs = 0, bgsLength, currentId, doInterval;
    wp1 = document.getElementById('wallpaper-1');
    wp2 = document.getElementById('wallpaper-2');
    divs = [ wp1, wp2 ];
    path = 'assets/img/wallpapers/';
    bgs = list.data;
    bgsLength = bgs.length;

    //Preload images
    for(var i = 0; i < bgsLength-1; i++) {
        var wp = new Image();
        wp.src = path+list.data[i];
    }

    function manageBg() {
        setInterval(function(){
            doInterval();
        }, 4000);
    }

    doInterval = function doInterval() {
        currentId = counterBgs % bgsLength;
        if (counterBgs % 2 === 0) {
            wp1.style.backgroundImage = "url(" + path + bgs[currentId] + ")";
            wp1.classList.add('animate');
            wp1.style.zIndex = 1;
            wp2.style.zIndex = 0;
            setTimeout(function() {
                wp1.classList.remove('animate');
            }, 5950);
        } else {
            wp2.style.backgroundImage = "url(" + path + bgs[currentId] + ")";
            wp2.classList.add('animate');
            wp1.style.zIndex = 0;
            wp2.style.zIndex = 1;
            setTimeout(function() {
                wp2.classList.remove('animate');
            }, 5950);
        }
        counterBgs++;
    };
    doInterval();
    manageBg();
});

Any ideas how to reduce the CPU overload?

like image 223
Igal Avatar asked Oct 18 '22 15:10

Igal


1 Answers

The answer is will-change property of css.

will-change is a property that optimizes animations by letting the browser know which properties and elements are just about to be manipulated, potentially increasing the performance of that particular operation.

Article Source: will-change - css tricks

The will-change property will use Hardware Acceleration in order to reduce load of your CPU and allocating your CSS3 animation/transformation to the GPU.

The Old: The translateZ() or translate3d() Hack

For quite some time now, we’ve been using what has been known as the translateZ() (or translate3d()) hack (sometimes also called the null transform hack) to trick the browser into pushing our animations and transforms into hardware acceleration. We’ve been doing that by adding a simple 3D transformation to an element that will not be transforming in three-dimensional space. For example, an element that’s animated in two-dimensional space can be hardware-accelerated by adding this simple rule to it:

transform: translate3d(0, 0, 0);

Hardware-accelerating an operation results in the creation of what is known as a compositor layer that is uploaded to and composited by the GPU. However, force-hacking layer creation may not always be the solution to certain performance bottlenecks on a page. Layer creation techniques can boost page speed, but they come with a cost: they take up memory in system RAM and on the GPU (particularly limited on mobile devices) and having lots of them can have a bad impact (especially on mobile devices), so they must be used wisely and you need to make sure that hardware-accelerating your operation will really help the performance of your page, and that a performance bottleneck is not being caused by another operation on your page.

In order to avoid layer-creation hacks, a new CSS property has been introduced, that allows us to inform the browser ahead of time of what kinds of changes we are likely to make to an element, thus allowing it to optimize how it handles the element ahead of time, performing potentially-expensive work preparing for an operation such as an animation, for example, before the animation actually begins. This property is the new will-change property.

The New: The Glorious will-change Property

The will-change property allows you to inform the browser ahead of time of what kinds of changes you are likely to make to an element, so that it can set up the appropriate optimizations before they’re needed, therefore avoiding a non-trivial start-up cost which can have a negative effect on the responsiveness of a page. The elements can be changed and rendered faster, and the page will be able to update snappily, resulting in a smoother experience.

For example, when using CSS 3D Transforms on an element, the element and its contents might be promoted to a layer, as we mentioned earlier, before they are composited in (drawn onto the screen) later. However, setting up the element in a fresh layer is a relatively expensive operation, which can delay the start of a transform animation by a noticeable fraction of a second, causing that noticeable “flicker”.

In order to avoid this delay, you can inform the browser about the changes some time before they actually happen. That way, it will have some time to prepare for these changes, so that when these changes occur, the element’s layer will be ready and the transform animation can be performed and then the element can be rendered and the page updated in quickly.

Using will-change, hinting to the browser about an upcoming transformation can be as simple as adding this rule to the element that you’re expecting to be transformed:

will-change: transform;

You can also declare to the browser your intention to change an element’s scroll position (the element’s position in the visible scroll window and how much of it is visible within that window), its contents, or one or more of its CSS property values by specifying the name of the properties you’re expecting to change. If you expect or plan to change multiple values/aspects of an element, you can provide a list of comma-separated values. For example, if you’re expecting the element to be animated and moved (its position changed), you can declare that to the browser like so:

will-change: transform, opacity;

Specifying what exactly you want to change allows the browser to make better decisions about the optimizations that it needs to make for these particular changes. This is obviously a better way to achieve a speed boost without resorting to hacks and forcing the browser into layer creations that may or may not be necessary or useful.

Article Source - Everything You Need to Know About the CSS will-change Property

Your css will be

.wallpaper {
    width: 100%;
    height: 100%;
    position: absolute;
    opacity: 0;
    background-repeat: no-repeat;
    background-position: center;
    background-size: cover;
    will-change: transform, opacity;
    -webkit-animation-timing-function: linear;
}

.animate {
    -webkit-animation-name: fadeInOut;
    -webkit-animation-duration: 6s;
}

@-webkit-keyframes fadeInOut {
    0% {
        opacity: 0;
        -webkit-transform: scale(1);
    }
    16% {
        opacity: 1;
    }
    90% {
        opacity: 1;
    }
    100% {
        opacity: 0;
        -webkit-transform: scale(1.1);
    }
}

Other Useful Sources:

  • Everything You Need to Know About the CSS will-change Property
  • CSS-TRICKS Article
  • SNOOK.CA
  • W3C Editors Draft
  • Mozilla Developer Network
  • Browser Support
  • will-change: update browser support
like image 125
Suresh Karia Avatar answered Oct 24 '22 02:10

Suresh Karia