Hello everyone, here is Yuki who uses a lot of animation to make her personal homepage and shooting game.

I feel that CSS animation is used too much, my MacBook is going to “strike”, back, I will give you a summary of my experimental results. Still want to use CSS animation

In this case

The purpose of this article is to add some complex animations with CSS animation in the web page, and then use the will-change attribute of CSS when doing some games or artistic expressions. How can GPU rendering be the most appropriate?

If you want to ask what will-change is? Take a look at the list of references I put in this article.

css-anime.firebaseapp.com/

The animation to be verified this time has the following points:

  • Draw 1000 flowers with CSS, one by one to do the animation of the painting
  • Each flower is a div element (not SVG this time)
  • Draw one at an interval of 32ms
  • After opening the flower, it stays in the picture
  • And the picture is always spinning

I don’t know if you’ve ever been in a painful situation where you have to animate, and you have to keep tagging, and then you have to keep showing, and you can’t disappear.

The experimental environment is as follows:

  • MacBookPro 2017Late / 8GB RAM (often referred to as the ‘mei’ minimum)
  • MacOSX Mojave
  • Chrome 74

And then WE’ll talk a little bit about Safari. Because it’s going to vary a lot from environment to environment, from browser to operating system, it’s going to vary a lot, so I’m going to explain that up front.

Standing on the shoulders of giants: an article I think is worth reading

Translator's note: The following links are all * Japanese *, I translated the title, Japanese ok students can point to see...Copy the code

Refer to the following link for this article:

  • CSS Will Change Module Level 1
  • CSS: Will-change Impact on Performance (Japanese version)
  • Best practices for CSS3 animation with high performance 60fps (Japanese version)
  • Preference for composit-specific attributes, and hierarchy management (Japanese version)

Experiment 0: Basic elements and animation construction

In order to start convenient, I will first write casually, I put the code posted also up, you see the code should also understand.

This is what HTML looks like. For ease and personal interest, Vue is used here. Any framework is ok.

Flower.vue

<div class="flower-root" 
  :class="{animate: visible}"
  @animationend="onEndAnim">
  <! -- -- -- > petals
  <div class="petal" v-for="(petal, index) in petals" :key="index"
    :style="{ transform: `rotate(${petal.r}deg)`, 'background-color': petal.col }">
  </div>
  <! - - - >
  <div class="center"></div>
</div>
Copy the code

The petals are built with divs, and the angles and colors are written in the template tag below. The bloom animation is also written here (that is, the animation has nothing to do with Vue and javascript, just CSS).

Flower.vue

<style lang="scss" scoped>
  .flower-root {
    position: absolute;
    transform: rotate(0deg) scale(0);
    animation: rotate 2s ease-out 0s 1 normal forwards;
  }
  .petal {
    position: absolute;
    width: 70px;
    height: 20px;
    top: -10px;
    left: 0;
    transform-origin: left center;
    border-radius: 50px;
    background-color: #ffb7aa;
  }
  .center {
    position: absolute;
    width: 30px;
    height: 30px;
    left: -15px;
    top: -15px;
    border-radius: 30px;
    background-color: #ffe683; } // Rotate it once to make it bigger@keyframes rotate {
    0% { transform: rotate(0deg) scale(0); }
    100% { transform: rotate(360deg) scale(1); }
  }
</style>
Copy the code

That’s what the flowers look like.

Have the Flower component add to the picture at regular intervals, and then the picture as a whole makes it spin.

Experiment 1: Just run (no will-change)

Instead of will-change, run an animation to open Chrome’s Performance Monitor panel.

Note: F12 -> CTRL + Shift + P is used to render the FPS panel. The GPU panel on the left is a native RENDERING on the MAC.Copy the code

The CPU is pretty good, it still keeps 60 FPS, oh, that’s not bad.

500. At about 400 or so, the CPU reached the bottleneck, and the frame count suddenly fell off. The browser was on the GPU, but the frame count still seemed to be very unstable.

Finally, the average frame count reached about 20fps, and the fans kept spinning loudly…

All the flowers were in bloom, leaving only 1000 motionless flowers spinning. At this point, I’m back to 60fps.

Conclusion of Experiment 1

  • CSS animations will increase CPU load as the proportion of elements increases.
  • When the CPU reaches a bottleneck, the frame count plummets.

Experiment 2: Use will-change for all

But how do you know until you try? The change is to add will-change: transform to the style.

Flower.vue

.flower-root {
  position: absolute;
  transform: rotate(0deg) scale(0);
  animation: rotate 2s ease-out 0s 1normal forwards; will-change: transform; / / append}Copy the code

Let’s start!

The 100th, very smooth, very low CPU load.

500. It’s starting to struggle a little bit. The GPU is like eating mustard.

Near the end, CPU and GPU are frantically “screaming”, performance is also very dangerous state.

The load does not drop after all the animation is finished. With will-change, the browser will not drop the load even after the animation is finished, in order to ensure the performance of any animation that will start at any time.

Conclusion of Experiment 2

  • Writing will-change will enable GPU acceleration
  • If there are too many elements with will-change, both the GPU and CPU will be overloaded
  • Writing will-change elements, even when the animation is over, still doesn’t lighten the load

Experiment 3: After the animation, delete the will-change style

Translator's note: To remove the will-change attribute means to set the will-change finger to the default auto, and all subsequent translations will be the same.Copy the code

The problem with Experiment 2 was that the flowering animation was already over, but will-change was still there. So in experiment 3, after the flowering animation, delete the will-change style.

In order to dynamically set the will-change property, we moved it to the template and added a variable to control it (we added an isMoving variable to Vue). Listen for the AnimationEnd event, in which the isMoving variable is changed.

Flower.vue

<div class="flower-root" 
    :style="{ 'will-change': isMoving ? 'transform' : 'auto', }"
    @animationend="onEndAnim">.Copy the code

Flower.vue

private onEndAnim() {
  this.isMoving = false
}
Copy the code

Delete only the value of will-change when the end of animation is detected.

So, start!

The 100th one feels good…

Five hundred, huh? The CPU is straining. The number of frames dropped to around 300. Because will-change is deleted after the animation is over, the GPU load is lighter, but the CPU load is heavier.

In the end, it was almost “strike”.

After all the animations were over, it was back to 60fps.

What the hell happened?

Oddly, the results are not so clear-cut. I just deleted the value of will-change right after the animation. What happened?

Update Layer Tree Update Layer Tree Update Layer Tree

This is handled internally in Chrome, and I don’t know exactly why…

See DevTools Timeline panel to understand browser rendering mechanism (Link in Japanese)

Update Layer Tree Updates the Layer processed by the GPU

That is, the GPU, in order to perform processing, puts elements that need to be processed on the layer, removes elements that don’t need to be processed from the layer, and then reconstructs them.

As a result of this trial and error, Chrome now has the following tendencies:

  • Update layer Tree elements that depend on layer will be heavier.
  • Demoting from layer is more costly than upgrading to layer, which means removing will-change is more costly.

I did not read the source code, these are just my guess.

Experiment 3 Conclusion

  • If the will-change attribute is deleted after the animation is finished, the GPU load will be affected
  • When GPU load is high, it will be difficult to set the value of will-change, especially to delete the will-change finger
  • When the animation ends under heavy load, deleting will-change values one by one is fatal

Experiment 4: Delete the value of will-change to some extent

In Experiment 3, when the animation ends, the values of will-change are deleted one by one, and the effect will be very bad. I don’t know why Chrome is trying so hard at this point, but I’ll see if there’s another way around it.

Deleting will-change once will cause the Update Layer Tree to be overburdened. So after saving a certain amount of breath to delete the words will be what? Try it right away.

Prepare the Flower queue

Flower.vue

const queueLimit = 100
const stopedFlowers: Flower[] = []
Copy the code

When the animation is over, add it to the queue. When it reaches 100, set isMoving and delete will-change in one go.

Flower.vue

private onEndAnim() {
  stopedFlowers.push(this)
  if (stopedFlowers.length === queueLimit) {
    stopedFlowers.forEach(fl= > fl.isMoving = false)
    stopedFlowers.length = 0}}Copy the code

Feels a bit opportunistic, ha ha. Experiment on!

At the 100th time, the animation started and will-change was carried with it. That is to say, the present state is the same as experiment 2.

The 500th, in units of 100, delete will-change, so every once in a while, the frames drop.

At the end of the day, this will continue, although there will be a few splintered frames, but overall, the load is fairly balanced.

After the last 100 runs are done, all elements are deleted with will-change. At this point, it’s the same state as experiment 1 and experiment 3.

Experiment 4 Conclusion

  • If will-change is saved to a certain extent after the end of the animation and then deleted, the effect will be better
  • When the will-change attribute is deleted, the load will become heavy, which is unavoidable (limited to the scope of this experiment).
  • I think it is necessary to watch the time to delete will-change when using animation extensively

Finally, let’s test safari

Running Safari on MacOS/iOS, the results of Experiment 3 were very smooth.

So if it’s not a Chrome bug, is it my use? Because I did not read the source code, so I am not sure. If you know, feel free to comment in the comments section.

conclusion

  • Add the will-change property for smooth CSS animation using the GPU.
  • Will-change deletes this property at the end of the animation.
  • In Chrome, will-change is deleted, Update the Layer Tree will rebuild the Layer, and the burden will become heavier. You can delete will-change every once in a while to minimize the impact.
  • Make sure you use different browsers and different environments. Don’t always think “Chrome is justice”.
  • Capture the validation performance monitoring panel, as well as the system performance monitoring panel. Even at 60fps, your machine might be screaming…

The translator to remember

Before, I only knew that Will-change will enable GPU rendering in the browser, but I did not expect that this will not be cool if it is used too much. There are also many points to pay attention to when using Will-change. If you need to use a lot of animation, you can refer to the practice of this article and delete the will-change attribute appropriately.

Original address: qiita.com/yuneco/item…