rich97
rich97

Reputation: 2879

Identifying cause of frames dropping using CSS3 animations

I'm trying to identify the cause of extreme slowdown in animations. As you can see (below) the paint times occasionally spike and cause the frames rate to drop to < 15 fps.

I can't show the site, but I can tell you that it's not lightweight on the front-end, it's a design showcase site, so there are plenty of large images animating in from outside of the view-port. I need to establish whether this is just something they're going to have to deal with or if anything can be done to reduce the paint times.

All of the animations are achieved using the translate() functions. The CSS for this particular set of animations follow:

.page {
    height: 100%;
    position: absolute !important;

    -webkit-transform: translateY(100%);
    transform: translateY(100%);

    /**
     * Override ng-animate-block-transition on this element. Has an important declaration.
     */
    -webkit-transition: transform ease-in-out 0.5s !important;
    transition: transform ease-in-out 0.5s !important;
}

.page.ng-show {
    -webkit-transform: translateY(0);
    transform: translateY(0);
}

.animate-in-enter-complete .page-peak .page.ng-show {
    -webkit-transform: translateY(-3%);
    transform: translateY(-3%);
}

.animate-in-enter-complete .page-peak .page.page-next {
    -webkit-transform: translateY(95%);
    transform: translateY(95%);
}

And here is a profile, which I did for this particular animation. The layer root is #document, I'm kind of new to these tools, but does that mean it's re-painting the entire DOM tree?

How can I find out what is causing that?

Screenshot of profiling tools

Upvotes: 5

Views: 4550

Answers (3)

Tim
Tim

Reputation: 1700

Optimization is just guessing without having a page to look at, but I can give you some thoughts that might be useful.

The CSS transform and opacity properties do not trigger layout or paint. It doesn’t matter if the animation is handled by JavaScript or CSS. Something else than the transform must be causing it. A full list of the work triggered by individual CSS properties can be found at CSS Triggers, and you can find a full guide on creating High Performance Animations on HTML5 Rocks. My guess is that you can do a lot of render tree, layout and paint optimization.

Use will-change to ensure that the browser knows what you plan to animate. 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. The elements can be changed and rendered faster, resulting in a smoother experience. In the case of your sample, adding will-change for transforms looks like this:

.page {
  will-change: transform;
}

Note: Do not use will-change on too many elements, it will cause the opposite. Currently Chrome, Firefox and Opera support this feature. It seems to get support from all modern browsers in the future.

Upvotes: 9

Andrea Ligios
Andrea Ligios

Reputation: 50271

23 seconds to paint one image is a bit too much. They don't need to "deal with it", just to find the bug. Because there is a bug, in the code, in the design (2337 images in a page, for example), or somewhere else.

Without being able to see the site, nor an anonymous fiddle reproducing its behaviour, nor even the HTML (!), and without knowing the number of images, their size, etc... the only possible answer left is:

enter image description here

Upvotes: 2

Brewal
Brewal

Reputation: 8189

Some new CSS3 features can be really heavy :

  • box-shadow combined with border-radius
  • filter (grayscale, blur, contrast, ...)
  • transform
  • ...

By enabling continuous repainting, you can see what rule is causing this load when disabling it. See this post

If you find that it is the transformation that is causing this load, that might be because the hardware acceleration is not used by the browser. You can force it by using 3D rendering that will not affect your transformation. One of these rules may do the trick :

transform: translateZ(0);
/* or */
transform: translate3d(0,0,0);
/* or */
perspective: 1000; 
backface-visibility: hidden;

If not, you may rethink your integration by wondering if the rule causing the load is actually essential.

Upvotes: 2

Related Questions