I was once asked how to achieve the following animation effects:

Several element cards are arranged from the top down, and when one card is added or removed, the rest of the cards move into place in a transition animation rather than a rigid flash

At that time, I happened to see the transition component in Vue, and I realized that I could use some of the principles of the Transition component to achieve this effect. But BECAUSE I hadn’t looked too deeply into why it was like this, I didn’t know why it was like this. So even though I knew how to achieve this effect, But it’s hard to explain why that is, it’s hard to organize. Right

Then I came across an article about the changes that FLIP technology was bringing to the Web layout, and it hit me. It was called FLIP

FLIP

FLIP is an acronym for First, Last, Invert and Play

First means that before anything happens, the position and size of the current element is recorded, that is, at the moment before the animation begins. This can be handled using the getBoundingClientRect() API (offsetLeft and offsetTop are also available in most cases).

Last: Executes a piece of code that changes the element and records the position and size of the element in the Last state of the animation, i.e. the moment after the animation ends

Invert: Calculate the position change between the First and Last position of the element (and, if necessary, the size change between the two states), and then use those numbers to do some calculations to move the element (transform the position and size of the element). To create the illusion that it is in the first position (the initial position)

That is, start with the element in the end state of the animation, and then use the Transform property to reverse the element back to the beginning state of the animation (the state information is available in the First step).

Play: To reverse the element (pretend to be in first position), we can set the transform to None, because without the constraint of transform, the element must be moved to where it should be (the state at the end of the animation), which is the position of last. If you add transition to an element, then the process naturally takes place as an animation

According to my understanding, it is a quantification of the start and end state of animation elements into a formula. Most of the continuous animation can be completed by applying this formula to improve the efficiency of animation development. For more details, please refer to the changes brought by FLIP technology to Web layout

Realize Card Card add and delete animation

Now that you know the concept of FLIP, it’s pretty easy to implement that animation

First

Record the position and size of each card before the animation starts. Since the size of the card does not change during the animation, you can skip this step and only record the position of the card

In addition, if all cards are of the same size, there is no need to record the position information of all cards, because when inserting or deleting cards, only those cards whose position coordinates are behind the changing card coordinates will be affected, not the ones in front

// First
activeList.forEach((itemEle, index) = > {
  rectInfo = itemEle.getBoundingClientRect()
  transArr[index + stepIndex][0] = rectInfo.left
  transArr[index + stepIndex][1] = rectInfo.top
})
Copy the code

Last

The end state of the animation is the state of the remaining cards after they have been added or removed:

if (updateStatus === 0) {
  // Add cards
  newListData = this.state.listData.slice(0, activeIndex).concat({
    index: cardIndex++
  }, this.state.listData.slice(activeIndex))
} else {
  // Delete the card
  newListData = this.state.listData.filter((value, index) = >index ! == activeIndex) }Copy the code

There is no transition attribute on the card, so the process of changing the number of cards takes a moment. The human eye does not notice any change, but the elements on the page do change, and then we measure the position of the card, which is the data required for Last

Invert

Once you have the position information of the card affected at the beginning of the animation, you can reverse the position of the element using the Transform property

// Last + Invert
const stepIndex = updateStatus === 0 ? 1 : 0
activeList.forEach((itemEle, index) = > {
  rectInfo = itemEle.getBoundingClientRect()
  transArr[index + stepIndex][0] = transArr[index + stepIndex][0] - rectInfo.left
  transArr[index + stepIndex][1] = transArr[index + stepIndex][1] - rectInfo.top
}
Copy the code

Play

Now that the ready stage is in place, we can Play the final step. The key to this step is to add the transition property to the element and remove the transform position:

// Play
/ / reset
transArr = getArrByLen(this.state.listData.length)
setTimeout((a)= > {
  this.setState({
    animateStatus: 3})},0)
Copy the code

Because the browser merges and optimizes the DOM changes on the page, this optimization must be interrupted in order to visually animate the page. SetTimeout is a common method

That’s it, the animation at the beginning of this article, I made a Live Demo, you can try it yourself, and the code can also be uploaded to Github

Realize picture enlargement/restore animation

When a preview picture is clicked in the chat interface of wechat App, a transition animation is used to show the whole process of the picture from small picture to large picture and from large picture to small picture. The zooming process is similar to the following:

This is also continuous animation, which can be easily done with FLIP

First

This involves the change of the position and size of the image. The original position and size of the small image in the First state are changed to the large position and size of the large image in the Last state. Therefore, the two data need to be obtained simultaneously

Last

Get the size and position of the image that is already in the preview state, again using getBoundingClientRect

In addition, in order to make better use of the transform animation, I change the size changes in the two states of the image into the change of the scale value, and the proportion of the width or height in the First and Last states is the value of the scale (without changing the ratio of the width and height of the image).

scaleValue = rectInfo.width / lastRectInfo.width
Copy the code

Invert

Use transform to reverse position and size (that is, change the scale value)

One thing to note here is that the default transform-origin of the transform animation is the center of the element, i.e. 50% 50%, but the calculated left and top are relative to the unscaled image, so when the scale value is not unique, The First state of the image animation is biased, and the transform needs to be set to 0 0 to eliminate this bias

Play

To start the animation, add the Transition property to the image and remove the associated Transform property

It can be seen that after the application of FLIP, an animation that originally looked tricky was easily modeled and realized

As for the stage of restoring the enlarged picture to the small one, it can be regarded as another FLIP animation, which can be continued, but this animation is the reverse of the previous enlarged animation. The required size and location information has been obtained, so the process of calling getBoundingClientRect can be saved

I also made a Live Demo, if you are interested, you can try it yourself, and the code can also be uploaded to Github

Why FLIP

Some people may be confused, if you want to implement animation, just transform, why bother with the concept of FLIP?

I had this problem at first, but when I actually implemented an animation, such as the card animation at the beginning, it was immediately answered.

For some animations, you know exactly what the First and Last states are. For example, you want an element to start from left:10px; Move to the left: 100 px; “, then you can just transform. There’s no need to FLIP.

But beyond that, some you can’t clear the initial state (First) or end state (Last) animation, such as the beginning of the animation, the card unless you limit died each card size and the size of the whole page, you can’t clear when you any insert or delete a card, other CARDS should be in what position.

For example, in your browser, each card is 100 wide and high, and the browser page is 1380 wide, so you can have 13 cards in each column, but that’s only in your browser, the user’s browser page width could be 1280, it could be 1980, and the number of cards in each column could be 12 or 19, You can even resize the page to any size you want. How do you determine the last status of all cards at any given moment?

You might say, of course I don’t know, but I can measure it using the browser API.

Sorry, that’s one of the things the FLIP does, and you’re still using it without realizing it, but your overall usage is probably a little more fragmented and irregular than what’s been summarized and optimized for.

As the title says, to make animation easier, you don’t have to use it, but if you know how to use it, then animation is a formula for you, a shuttle, much easier.

summary

Many front-end students seem not to care much about animation, thinking that it is just an auxiliary ability, business logic is the most important, and other things are all behind, even if they have time, they will decide whether to do it or not according to their mood

My view is that the business logic is to first, of course, but also do not look down upon the rest of the details, such as animation, an experience good dynamic effect can attract more users to stay, in a general way of business transformation from the side effects, some specific scenarios, it can play a role of can even keep pace with business objectives