I want you to listen to me. You cannot animate whichever CSS property you’d wish to transition carelessly. You just can’t. Get over it. In fact, let’s make a vow:
I will not transition width, height, margins, or any other CSS property for that matter, without having consulted csstriggers.com beforehand
Many people I talk to think it’s lame that web developers can’t transition what they want without incurring in jank and scrolling issues, but that’s the reality of things and this fact is not going anywhere soon; so let’s stop complaining and see what we can do to start helping to make the web a better (and smoother) place.
Let’s take a step back here and stop ranting for a minute, what’s this thing about animating the right CSS property?
I’ll give you the TL;DR first: most CSS properties force expensive recalculation on the browser whenever their value changes, therefore, transitioning those properties over time result in continuous “expensive recalculations” many times per second and the corresponding animation will look laggy.
But why exactly does making the browser compute a lot of stuff affect an animation’s performance? Where does jank come from?
During an animation, many frames follow one another in a regular and consistent sequence. The illusion of movement is given by the rapid alternation of pictures, or frames, each one representing a slightly different state of the motion. Jank, or lag, in an animation is the visible manifestation of the renderer skipping a frame. In other words, whenever a frame lasts on screen sensibly longer than the others, lag is perceived.
That’s ok, but why would that happen? What’s the root cause of jank? The main reason for a frame to stay on screen longer than needed, is the following frame not being ready. This is way more common that one may intuitively think, in fact every time that, in between frames, the main thread is busy computing and preparing the next frame, you end up skipping one. Unfortunately, in the browser things are much more complicated than that.
Let’s see what could keep the browser busy during the duration of a frame (Pic shamelessy stolen from Google Developers’s article, which you should read):
This is just a simplified picture of reality, if you’re interested in diving deeper I highly suggest that you go check this article out by Paul Lewis. What is important to notice, however, is that every one of these steps can be subject to delays, thus causing jank.
Some steps of the pipeline above can be handled by another component inside your device: the GPU. Specifically, the Composite part can be offloaded to it; why does it matter? Well, the GPU is a great piece of technology specifically built and optimized to execute multiple independent computations in parallel! The benefits can be summed up as follows:
As we understood earlier, in order to reduce jank we need to prepare the next frame in the smallest period of time possible. Wouldn’t it be great if the browser process could let the GPU compute the next frame, while it’s busy taking care of all the rest? Turns out it can. With a little help by us.
In fact, not all CSS properties are made equal. When their value changes, some of them trigger a complete repaint, some of them cause the browser to recompute layout information, some of them only need compositing to take place. A-ah! Therefore, one could animate only these CSS properties and achieve great performance!
So what can we do, practically, to act on this knowledge? Let’s break it down:
Actually there’s a litte bit more to it. transform and opacity can, indeed, be handled by the GPU, since a stacking context is created when their value is set. In other words, whenever their value changes, none of the other elements in the page get affected in any way. What this implies is that they can be managed in different layers: as a consequence, if we transition transform, for example, at every frame there is just the need to composite the layers together.
Since the creation of a stacking context is essential for this scenario to work out, developers can declarative hint the browser that an element is expected to change its transform value in the near future, so that it can create such context upfront. How? By specifying a will-change: transform CSS property on that element. The browser (and your users!) will thank you, and promote such an element to its own layer.
Will do! This is a huge topic, and many people wrote on this. Here are some pointers to learn further:
I hope you found this helpful! Follow @westwingsols for daily #WebPerformance tips. If you think this might be useful to someone you know, please share it to let us reach more people! Also, we’d love to hear your feedback on this type of articles. Is it helpful? Would you rather read something more practical or theoretical? Let us know, by leaving a comment on Twitter!
If you feel this might interest someone else, please leave an heart to help us reach more people! Comments and thoughts are appreciated as well ;)
This article was originally published on the West Wing Solutions blog, a collection of learning material for professionals who are eager to explore the science behind building a successful online product.