ccforward/cc

21.优化 CSS 动画性能

Opened this issue · 0 comments

极可能的加速 CSS 动画性能

最近在研究 web 性能优化的问题,看了来自Google的文章《FLIP your animations》

这篇文章提供了一种优化动画性能的方法,但是实现起来略微复杂,不过前端界本来就是各种 Hack 大行其道,所以简单了解了下其原理:

通过在100ms的动画响应延迟窗口期内计算动画初始与终止的属性差值,把动画尽量转换为只变化transform或opacity这类只触发重组不会触发重绘与重排的属性。

100ms

关于什么是动画响应的延迟时间,为什么会是100ms?100ms可以说是人类大脑的时间常量值,如果一个动作在触发后立即执行,视觉上就会有一种违和的感觉,而延迟100ms才响应的体验是让人感到最舒服的,关于100ms延迟具体细节可以查看人机交互领域大师的这几篇文章:

PS: 上面文章之前同事有推荐过,但是具体内容我没有细看。

动画实现

整个动画过程的实现代码大概如下:

  // 1. 获取开始位置的状态
  var first = el.getBoundingClientRect();

  // 2. 通过添加样式类设置元素为最终位置的状态
  el.classList.add('at-the-end');

  // 3. 获取最终位置的状态
  var last = el.getBoundingClientRect();

  // 4. 计算初始与终止位置状态的差值,这里只计算top属性为例,通常需计算以下属性差值:left、top、width、height、scaleX、scaleY、opactiy
  var difference = first.top - last.top;

  // 5. 通过transform设置位置偏移
  el.style.transform = 'translateY(' + difference + 'px)';

  // 6. 等待下一帧生效,确保第5步已经生效
  requestAnimationFrame(function() {
    // 7. 添加样式类,让动画跑起来
    el.classList.add('animatable');
    // 8. 重置transform
    el.style.transform = '';
  });

  // 9. 动画结束后移除添加的类
  el.addEventListener('transitionend', function transitionend() {
    el.classList.remove('animatable');
    el.removeEventListener('transitionend', transitionend)
  });

关于 requestAnimationFrame 的使用,写了一段兼容代码:
requestAnimationFrame.js

其中 animatable 样式规则如下,transition-property 设置为 tranformopacitytransition-durationtransition-timing-function 可按需求自定义设置:

  .animatable {
      transition: transform 1s linear, opacity 1s linear;
  }

我个人认为,无论何时,性能优化总是不能达到极限,所以性能优化要一直持续下去。