Performance monitoring in CSS animations
This question hits every developer once, or probably twice or more, in their technical career.
The foundation of animation relies on some CSS properties that you will often use in CSS based animation heavy implementations.
position: (absolute /relative)
left, right, top, bottom and many more.
Let’s begin by looking at the results from two experiments with different CSS properties for animation.
(a) position absolute with left and top
Additionally, why don’t we try to draw conclusions on performance and rendering time based on these experiments?
By looking at these two examples, it feels that similar functionality has been implemented despite using different approaches. However, when we measure the performance metrics in chrome dev-tool, we see an actual difference in terms of performance for both cases.
Before we deep dive to understand these performance metrics we need to understand how the browser renders UI and all of the actions it performs when any update happens on UI.
So the UI creation starts with the:
1) Calculate the styles which are going to apply to the elements (Recalculate Style)
2) Create the layout of the elements and position them on screen(Layout)
3) Add the pixels in all created layouts, it’s more of creating bitmap for each layer. GPU uses this bitmap to render the layer on screen (Paint)
4) Lastly, create the layers on screen, constructing a stack of layers. The top view of this stack will be look like a complete webpage in which every element has its own position(Composite Layers)
Composite Layer creation is a place where CPU talks to GPU, to handle the animation. Using properties like transform and opacity, we can force the browser to do animation using GPU instead of CPU.
So how does GPU help us to perform a smooth animation?
GPU is another small machine to handle our animation and it can handle a large number of UI calculations.
So, when Composite layer creation triggers, it creates another layer. This is another way to helps us avoid re-rendering the element which is getting animated and other parts of the UI elements.
In the picture below, both red balls look to be on the same layer. But, when we move this layer in 3D rotation, we find that the Transform animation has another layer that has been created for the red ball, providing smooth animation.
GPU keeps this render object tree in memory and, without rendering again, can put this layer on top of the others. But, in the case of animation in the top-left, the same layer is getting rendered again and again due to changes in these properties. If we check the behaviour of these two CSS properties, we will see that both the properties left and top impact the layout, also causing a repaint and composite operation.
Translate vs Top / Left
The above animation of the ball has a clear difference between translate vs top/left.
In the case of top/left animation, the ball is getting rendered on each position until it reaches the final destination and, when it starts moving to the initial position again, it starts the rendering part.
Note: The Purple color represents the layout creation of the red ball and the green color is used to file the pixels.
Both pictures above are a screenshot of how translate performs vs top/left.
By highlighting a single task of each one, we begin to understand that the activity performed by the task is different in both cases. In the top/left case, the task performed layout creation, painting, and style recalculation. In the case of translate, a single task performed by the GPU moves the composite layer without rendering anything in DOM.
So, with GPU power, we are keeping our main thread free. This helps us boost application performance and our main thread is busy rendering layout.
The above performance metric graph provides more evidence, explaining the exact extent our main thread is busy in layout and style recalculation. This graph is continuously reflecting the changes happening on the UI.