惯例BB
最近在做一个卡片弹窗的动画,怎么做都达不到想要的效果,查了查资料,发现通过一种叫FLIP的技术(也不算新技术,一种思路?),可以比较好的实现这个效果,而且这个过程中,也了解到了一些关于动画性能相关的知识,所以记录一下。
类似效果
关于FLIP
FLIP是First、Last、Invert和Play四个单词首字母的缩写。
简单解释下这四个单词在实现思路中对应的意思
- first:指在过度效果发生前,目标对象的位置、大小
- last:指过度效果发生后,目标对象的位置、大小
- invert:目标对象过度前后的位置、大小差
- play:通过invert得到的差值,来作为transform的参数进行动画
实现思路
1.动画前后的效果,用两个div写好
2.获取这两个div的大小比例和位置差
3.通过translate将动画后的div变成动画前的大小和移动到对应的位置
4.通过取消3中的translate和重新设置,加上过度就可以实现动画效果啦
手撕代码前
代码使用到的API
transform:translate/scale
getBoundingClientRect
关于性能
上图中的layout和paint是非常影响性能的,比如position和display控制显示隐藏,都会触发这两步,所以在动画过程实现中,位置用transform的translate、显示隐藏用visibility/opacity 来做。因为他们只会触发最后一步。
代码演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| ... <style> body { margin: 0; position: relative; }
div { text-align: center; background-color: rgb(139, 206, 248); }
.before { width: 300px; height: 300px; line-height: 300px; margin: 0 auto; transition: all 1s; }
.after { width: 100vw; height: 100vh; line-height: 100vh; position: absolute; top: 0; } </style> ... <body> <div class="before"></div> <div class="after"></div> </body> <script> let before = document.querySelector('#before'); let after = document.querySelector('#after');
let first = before.getBoundingClientRect();
let last = after.getBoundingClientRect(); console.log(first); console.log(last);
let invert = { left: first.left - last.left, top: first.top - last.top, width: first.width / last.width, height: first.height / last.height, };
after.style.visibility='hidden'; after.style.transformOrigin = 'top left'; after.style.transform = `translate(${invert.left}px,${invert.top}px) scale(${invert.width},${invert.height})`;
before.addEventListener('click', function () { after.style.transform = ''; after.style.transition = ' all 1s'; after.style.visibility='visible';
});
after.addEventListener('click', function () { after.style.visibility='hidden'; after.style.transition = ' all 1s'; after.style.transform = `translate(${invert.left}px,${invert.top}px) scale(${invert.width},${invert.height})`; }); </script> ...
|
参考链接
浏览器渲染原理
前端动画之FLIP技术