How to develop fast web animations by using FLIP and RAIL techniques
How to get your animations to render fast as lightning
Let's say a
<div> element needs to be rendered on a web page. Then the browser first looks at what that element should look like. This is the '(re)-calculate' phase. Here we look at the CSS that gets the
<div>. Then we look at the 'bigger picture'. This happens in the 'Layout' phase. It looks at where this
<div> should be placed on the page. When that planning phase ('Recalculate style' and 'layout') is over, the
<div> can be drawn ('paint' phase) on the page.
Since we are talking about performance within web animation and renders, we want to make sure that the browser has to do as little as possible. We will try to achieve that by not animating css properties such as width, height, top, left and the like. If you try to animate these properties, all three rendering phases will be started again. If we use css properties like 'Transform: translate' instead, the browser only needs to calculate where the element should go.
The phases printed in yellow (in the example above) are phases calculated by your GPU (graphics card). 'Paint', the blue printed phase, is calculated by your CPU. It is a lot slower in making calculations. So you want to use the CPU as little as possible. You can take care of that by using
You have to see it this way. Suppose that I want to make a drawing of a figure. Then, I first think about how big that figure should be ('(re)-calculate style'), where that figure should be on the drawing ('layout'). Finally, I have to actually draw the figure (‘paint’). If I then want that figure to appear on the right side of my drawing, I will have to erase it first and start drawing again.
This is what also happens when animating width, height, top and left. But, I can save myself (the CPU) a lot of hassle, if I cutout and move the figure. Then I no longer have to look at where it needs to go, because it is shifted relatively from its previous position and I no longer have to erase it and draw it again. All I have to do is move the figure.
That's how it works on the web. You save the browser a lot of computing power by shifting something via, for example,
transform: translate3d(x, y, z). If you make something shift by adjusting the margins, left, height or width, it has to recalculate the layout with every frame and 'paint' the page again.
We just talked about a cutout figure. This figure now has its own layer above the rest of the paper. A nice word for this is: "layer promotion". But how do you give an HTML element its own layer?
You can do this, for example, with
transform: translate3d(x, y, z). The browser then thinks “oooh 3d, this can get complicated, I'll give it its own layer”. This is super beneficial, because again this means you only load your CPU once, instead of every frame in your animation.
If you have placed an element on a web page. Do you know exactly how far this element is from the left side of the screen? Don't worry, I don't know this either.
.getBoundingClientRect() knows this. By selecting your element, in this case
<div id=“foo”>, with the
querySelector, you can get data like 'left, top, width etc' from this element by using
.getBoundingClientRect. Your code will then look like this:
const fooCoords = document.getElementById(‘foo’).getBoundingClientRect()
The constant 'fooCoords' now contains an object with all dimensions and coordinates of your
I can imagine you are now wondering, “I thought this talk was about web animation. What does .getBoundingClientRect() have to do with this?”.
Let's say you have an e-commerce website, and you want that when someone clicks on your product, the product flies into the shopping cart. Then you first calculate the current position of the image of the product you click on and then the current position of the shopping cart. Since you now know (thanks to .getBoundingClientRect()) the coordinates of both elements, you can calculate how many pixels the photo of the clicked product has to move to get to the shopping cart. We call this difference 'deltaX' and 'deltaY'. If we give these values to a transform, your element moves to the shopping cart. Just don't forget to give that image a
Flip is a pattern created by Paul Lewis. A scholar when it comes to performance, web animation and the combination thereof.
FLIP stands for First, Last, Invert, Play. But what does this mean?
The FLIP method works as follows.
- You collect the coordinates of an object (in the example below for example from the photo of the Potato (
<img class=“photo” src=“potato.png”/>)). You store this in a constant.
- You give that image a class, for example '.fullSize'. For example, this class contains
width: 100vw; height: 100vh;. Then you also store those coordinates, but in a different constant.
- You remove the class as soon as possible. We no longer need these and will no longer use them.
Just for clarification. These steps all happen while rendering the page. Since this can be calculated so quickly, it happens even before the paint. Because of this you will not see a flash of a, in this case, gigantic potato.
We call the function
animate() on photo.
animate() has two parameters. First an Array with keyframes and then an object with settings. Since we only have two keyframes, you can think of it as a
from-to animation. In the object you indicate how long the animation should last, you optionally give easing, fill and direction and then you have made your FLIP animation. Now you just have to make sure that your animation is called in response to an 'event' and you're done.
According to the RAIL principle (Response, animation, idle, load), your response should not last longer than 100ms. Normally, the response of a click event takes about 10 - 30 milliseconds, so FLIP still has about 70ms to do its calculations and generate keyframes. We do this to make the A of RAIL, Animation, run as smoothly as possible. According to the RAIL principle, you have to play animation at 16ms per frame. Better known as 60 frames per second.
Finally, I would like to inform you that not everyone likes flying potatoes in their screen. Some people can't handle animations or moving images themselves. There are people who experience motion sickness when they visit pages with movement in them. To keep the web as accessible as possible for everyone, it is important to take this into account. So always make sure to apply the media feature
@media(prefers-reduced-motion) to animation elements. This can be done very easily and only takes a few seconds of work.
Other posts you might like
How to develop a Web AR Facefilter with React and ThreeJS / React Three Fiber in 2021September 09, 2021
For the 3 year anniversary of 🧙🏼♂️ Level30Wizards we wanted to build something that's related…
Accessible Wavy Text Animation using React Hooks and Framer MotionFebruary 17, 2021
In this article i'll recreate a wavy text animation we built with React Hooks and GSAP v3 but…
How we drove up sales with animation and storytellingOctober 05, 2020
“Good animation is invisible. You shouldn’t notice that you’re looking at animation. You want to…