作为一名前端开发者,项目中我们会经常实现一些动画效果,这些动画通过设置height
、width
、top
、left
或者除了transform
、opacity
其他的属性值来完成。您可能已经注意到,这些动画技术已经有些过时,这其实是有原因的。当任何触发布局更改的属性(比如height
)变化时,浏览器都必须检查其他元素的布局是否发生了改变,这代价是很昂贵的 浏览器的回流与重绘 (Reflow & Repaint)。如果计算所花费的时间超过了一个动画帧(大约16.7毫秒),则该动画帧将被跳过,因为该帧没有及时渲染,所以页面有时会出现卡顿的情况。在保罗·刘易斯(Paul Lewis)的文章Pixels are Expensive,他深入探讨了如何渲染像素以及各种性能支出。
简而言之,项目开发过程中,我们要尽量减少一些必要样式修改所导致的浏览器回流操作。FLIP技术可以很好的帮助我们如何仅使用transform
和opacity
来模拟一些常见的布局修改动画。
在css动画中,除了 transform 和 opacity 之外的动画开销都比较大(包括left、top等定位元素),动画会有一点迟滞,因为浏览器必须递归检查其他元素的布局是否因此而改变。
所以Flip就是一个仅仅通过transform这个属性来实现流畅无延时的动画的技术。
简单来说,FLIP就是记录一个元素变化前和变化后的状态,然后通过JS模拟重播这一动画的过程。
FLIP 是 First, Last, Invert, Play 的缩写,最早由 Paul Lewis 提出
element.getBoundingClientRect()
。transform
修改其位置和尺寸来创建它位于 First 位置的错觉。(我们已经知道了过渡元素的初始和最终状态,所以我们可以很清楚的了解元素的变换方式,比如宽度、高度和不透明度的变化,接下来,通过修改transform和opacity使过渡元素仍然保持初始状态,比如过渡元素的最终形态是向下移动90px,那么我们可以设置translateY:-90px来是元素看起来仍然在初始位置。)transform
设置为none
,将其移回到 Last 位置。(上一个操作中,元素虽然已经处于最终状态,但是看起来仍然是在初始位置,这时候我们可以赋予元素transition动画,并初始化已经应用的transform和opacity样式,我们可以看到过渡元素会自然的过渡到最终状态)以下是如何使用Web Animations API实施这些步骤:
<aside> 🚨 注意:并非所有浏览器都支持Web动画API。但是可以使用polyfill。
</aside>
https://codepen.io/davidkpiano/pen/EbwrQQ
从交互结束到感知到响应大概需要 100ms 的生理反应时间,如果网站能在这 100ms 内做出响应,那么对用户来说就相当于网站立即进行了响应,然后只需要保证动画在 60FPS 运行就能给用户带来最佳的体验。
我们可以充分利用用户 100ms 生理反应时间来进行相关的计算:getBoundingClientRect 或 getComputedStyle,并通过 FLIP 技术使动画尽快开始,最后通过 transform 和 opacity 的动画来保证动画的平滑运行。
FLIP 技术带来的改变对于 PC 端可能并不是那么明显,但对于 CPU 并不算非常强大的移动端却是相当显著。
我们可以通过工具,例如 CSS Triggers 来查看哪些属性会在动画时触发重绘。在工具中,查看 transform
的相关内容,你将看到:
非常好的是,更改 transform 不会触发任何几何形状变化或绘制。这意味着该操作可能是由合成器线程在 GPU 的帮助下执行。
opacity
属性的行为也类似。因此,他们是在 web 上做元素移动的理想选择。
诸如 perspective
、backface-visibility
和 transform:translateZ(x)
等 property 将让浏览器知道你需要硬件加速。
如果要对一个元素进行硬件加速,可以应用以下任何一个 property (并不是需要全部,任意一个就可以):
perspective: 1000px;
backface-visibility: hidden;
transform: translateZ(0);
许多像 GreenSock 这样的 JS 库都会默认你需要硬件加速,并在默认情况下应用,所以你不需要手动设置它们。
对于简单 UI 过渡,即从一个状态到另一个没有中间状态的状态,通常使用 0.1s 到 0.4s 之间的计时,大多数人发现 0.25s 是一个最佳选择。你能用这个定时做任何事情吗?并不是。如果你有一些元素需要移动更大的距离,或者有更多的步骤或状态变化,0.25s 并不会有很好的效果,你将不得不有更多的目的性,而且定时也需要更加独特。但这并不意味着你不能在应用中重复使用效果好的默认值。
你也可能会发现,起始动画比结束动画的时间稍长一些,看起来会更好一些。用户通常是在动画开始时被引导的,而在动画结束时没有那么多耐心,因为他们想继续他们的动作。
https://codepen.io/wzc570738205/pen/VwaNmxg?editors=1010
https://codepen.io/MrLeo/pen/NWRyWpg
https://codepen.io/MrLeo/pen/YzGezjq
Flipping.js : 通过向 data-flip-key="..." HTML元素添加属性,可以可预测和有效地跟踪可能因状态而异的位置和尺寸的元素