When it comes to developing for the web, there is almost always another way or a better way to achieve what you’re after; transitions and animations are no exception. Below you’ll find a few of the techniques that I use to achieve smooth element transitions and animations on the web.
Here is quick list of techniques that you may want to use to ensure that your animations are performing as smooth as possible.
1. Use CSS properties that only require compositing changes
To perform a transition or animation on an element, you’re going to be modifying the properties of that element. When the value of an element’s property changes, it will trigger a change in either the layout, paint or composite (or potentially all three) within the browser. Our goal is to use properties that only trigger the composite (and to avoid triggering a paint). The details on which properties trigger which events can be found at CSS Triggers.
A quick scan through the list of CSS triggers reveals that the two properties that you’ll want to stick to when performing transitions and animations are:
2. Promote elements that you’re going to be animating
You can promote elements by applying the will-change CSS property to them. By applying will-change to an element, you are giving the browser a heads up of the kind of changes to expect from that element. This allows the browser to perform the necessary optimizations ahead of time before the element is actually changed.
will-change accepts multiple values that are comma separated.
will-change: opacity, transform;
Warning: avoid applying will-change to too many elements. Promoting elements requires resources. If you promote too many elements, you run the risk of doing more harm than good.
There are a number of reasons why you should use requestAnimationFrame over setTimeout or setInterval. These include:
1. The timing between intervals of the requestAnimationFrame method is much more consistent and results in smoother animations. When visual changes happen within the browser, you want to ensure that your code runs at an optimal time. When your animation is using requestAnimationFrame, your code will run at the start of the frame. But when your animation is using setInterval, you are not guaranteed this and the callback may potentially run at the end of the frame, which could result in a dropped frame.
2. requestAnimationFrame calls will pause while running in the browser’s background tabs. This improves performance and prevents negatively impacting other animations and actions running on the currently active browser tab.
3. setTimeout and setInterval don’t take certain things that are happening in the browser into consideration. These methods try and make the browser update the animation while it is potentially already performing a redraw on the entire screen. This is where requestAnimationFrame excels by requesting that the browser executes the code at the next available repaint.
The goal is for our transitions and animations to perform as smooth as possible. To do this, we’re going to try and avoid changes that are expensive to process and cause unnecessary browser repainting (which can result in jank). Jank is what causes the content on the screen to jolt or stutter from dropped frames.
1. Don’t update CSS properties that will cause painting to occur
As mentioned in the first point of The Do’s, you’ll want to check in with CSS Triggers to see which properties trigger a paint … and not use them.
Commonly made mistakes involve changing properties like padding, margin, or top/left/bottom/right to move an element. The most efficient way to move an element would be to translate it using the transform property.
2. Avoid unnecessary layering
The benefit of promoting elements to their own layers to perform animations is gained from reduction in the amount of area that needs to be repainted. But since layering is expensive, with each layer requiring memory and management, it’s possible to overdo this technique and have a negative impact on the performance of devices with limited memory.
3. Avoid layout thrashing
- Try to only use opacity and transform to perform your animations and transitions
- Promote elements that will be animated by using will-change or transform3d/translateZ
- Don’t over-promote elements