js css html

FLIP 动画技术

2022-06-29  本文已影响0人  alue

如果用 height, width, top, left等CSS属性来做动画,性能要远远差于用 transformopacity属性的动画。动画元素多的话,前者会带来页面卡顿。

这是因为不同的动画,涉及浏览器的不同阶段:Layout ➠ Pain ➠ Composite。如果单独触发 Composite,那么浏览器的负担就很小,动画会很丝滑。

When any property that triggers layout changes (such as height), the browser has to recursively check if any other element’s layout has changed as a result, and that can be expensive.

触发布局的属性一旦发生变化,浏览器就会非常忙碌.它需要递归的计算其它元素的布局是否会发生变动.

一旦这个计算时长超过1个动画帧(一般是60帧每秒,也就是说超过16.7ms), 那么这帧动画将不会绘制,产生页面卡顿。

FLIP动画技术,就是只利用transformopacity模拟布局变动的技巧,因为它不触发Layout,所以动画比较丝滑。

FLIP是 First, Last, Invert, Play的简称。

First

对应动画的Start阶段,用 element.getBoundingClientRect()记录初始位置。

Last

对应动画的End阶段,先执行触发layout变动的代码,记录元素的终止位置。

Invert

现在元素处于End位置,利用 transform 做一个逆运算,让添加了 transform 的元素回归到初始位置。

Play

真正需要执行动画时,将 transform 置为 None.

采用Web Animations API的代码示例如下

const elm = document.querySelector('.some-element');

// First: get the current bounds
const first = elm.getBoundingClientRect();

// execute the script that causes layout change
doSomething();

// Last: get the final bounds
const last = elm.getBoundingClientRect();

// Invert: determine the delta between the 
// first and last bounds to invert the element
const deltaX = first.left - last.left;
const deltaY = first.top - last.top;
const deltaW = first.width / last.width;
const deltaH = first.height / last.height;

// Play: animate the final element from its first bounds
// to its last bounds (which is no transform)
elm.animate([{
  transformOrigin: 'top left',
  transform: `
    translate(${deltaX}px, ${deltaY}px)
    scale(${deltaW}, ${deltaH})
  `
}, {
  transformOrigin: 'top left',
  transform: 'none'
}], {
  duration: 300,
  easing: 'ease-in-out',
  fill: 'both'
});

注意

  1. 要设置 transform-origin: top left
  2. 可以采用第三方动画库来实现FLIP

提出FLIP动画技术的大牛 David Khourshid 还专门编写了Flipping.js,可以更加方便的实现高性能FLIP动画。

上一篇下一篇

猜你喜欢

热点阅读