IOIIOOIO
IOIIOOIO

Reputation: 4209

Poor CSS Animation performance - no browser paints

I've got a number of elements that I'm animating which I've developed in a manner that shouldn't cause any browser paints. If I turn on "Paint Flashing" in Chrome Devtools I don't see any paint flashing at all. However, if I record the performance then the graph shows that there is a lot of time spent on painting. The FPS is as low as 15fps at times.

I actually built this in Vue, and the compiled code results in too much code to paste here. I realise the animation is somewhat broken, I still need to work out some timings etc - but for the purpose of this question, I'm only concerned about the performance.

I have posted the compiled code here on CodePen:

https://codepen.io/IOIIOOIO/pen/gjBqyg

It seems StackOverflow requires that I post some code here, so here is the compiled code for just one element:

.circle {
  position: relative;
  width: 100%;
  padding-top: 100%;
  border-radius: 50%;
  overflow: hidden;
}

.circle::before {
    content: "";
    background-color: black;
    position: absolute;
    top: 0;
    left: 0;
    width: 50%;
    height: 100%;
    animation-name: switch;
    animation-iteration-count: infinite;
    animation-timing-function: steps(1);
    animation-duration: 3s;
    animation-delay: inherit;
  }

.rotating-circle {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
}

.rotating-circle--first-cycle {
    background-color: black;
    animation-name: rotate, toggle-first;
    animation-duration: 3s, 3s;
    animation-iteration-count: infinite, infinite;
    animation-timing-function: linear, steps(1);
    animation-delay: 1800ms;
  }

.rotating-circle--second-cycle {
    opacity: 0;
    animation-name: rotate, toggle-second;
    animation-duration: 3s, 3s;
    animation-iteration-count: infinite, infinite;
    animation-timing-function: linear, steps(1);
    animation-delay: 1800ms;
  }


@keyframes rotate {
  0% {
    transform: rotate3d(0, 1, 0, 0deg);
  }
  50% {
    transform: rotate3d(0, 1, 0, 180deg);
  }
}

@keyframes toggle-first {
  0% {
    opacity: 1;
  }
  25% {
    opacity: 0;
  }
  75% {
    opacity: 1;
  }
}

@keyframes toggle-second {
  0% {
    opacity: 0;
  }
  25% {
    opacity: 1;
  }
  75% {
    opacity: 0;
  }
}

@keyframes switch {
  0% {
    transform: translatex(0);
  }
  50% {
    transform: translatex(100%);
  }
  100% {
    transform: translatex(0);
  }
}
<div class="circle" style="background-color: rgb(255, 0, 0); animation-delay: 0ms;">
  <div class="rotating-circle rotating-circle--first-cycle" style="animation-delay: 0ms;">
  </div>
  <div class="rotating-circle rotating-circle--second-cycle" style="background-color: rgb(255, 0, 0); animation-delay: 0ms;">
  </div>
</div>

Upvotes: 3

Views: 739

Answers (1)

IOIIOOIO
IOIIOOIO

Reputation: 4209

It seems that all the work was being done on Composite Layers, and not necessarily on Painting alone. I found that adding transform: translateZ(0) or will-change to the individual elements that were being animated didn't help much. However, if I add transform: translateZ(0) to the parent .circle element then the time spent on Composite Layers and Painting is greatly reduced.

It still runs fairly slow but I think that may just be because my computer has onboard graphics and 4GB of RAM.

So I think this is as good as it will get but would appreciate any further suggestions.

Here is an example where I've added transform: translateZ(0) to the parent element:

https://codepen.io/IOIIOOIO/pen/gjBqyg

EDIT:

I've found a significant improvement by removing border-radius on the parent, which I had set to overflow: hidden to create a mask:

Before:

.circle {
  border-radius: 50%;
  overflow: hidden;
}

Instead, I used clip-path as a mask:

After

  transform: translateZ(0);
  clip-path: circle(49% at 50% 50%);

I'm sure you'll notice straight away it's much better:

https://codepen.io/IOIIOOIO/pen/OwBBJV

Any further insight into why this works would be much appreciated.

Upvotes: 5

Related Questions