Skip to content

前端动画(一) #181

Open
Open
@louzhedong

Description

自从有了前端开发这个概念以来,其实这个岗位所做的事情都是围绕着人机交互来开展的,主要包括展示信息给用户看,然后获取用户的意图并做出响应。一个高质量的动画在很多情况下都能大大提升用户的视觉体验。

实现动画的方法

  1. 视频或GIF图片
  2. Flash
  3. 通过JS改变DOM节点的CSS属性
  4. Canvas
  5. WebGL

动画渲染技术的趋势

Canvas + WebGL

前端动画分类

  1. JavaScript控制的动画
  2. CSS控制的动画
JS动画

JS动画的原理是通过setTimeout setIntervalrequestAnimationFrame 方法绘制动画帧(render),从而动态地改变网页中图形的显示属性(如DOM样式,canvas位图数据,SVG对象属性等),进而达到动画的目的。

多数情况下,应 首先选用 requestAnimationFrame方法(RAF),因为RAF的原理是会在浏览器下一次重绘之前更新动画,即它的刷新频率和浏览器自身的刷新频率保持一致(一般为60Hz),从而确保了性能。另外RAF在浏览器切入后台时会暂停执行,也可以提升性能和电池寿命

CSS动画

css动画有以下特点:

优点

  • CSS动画实现比较简单
  • CSS动画执行与JS主线程无关,例如在Chromium里,css动画运行在compositor thread线程中,即使你js线程卡住,css动画照常执行
  • 强制使用硬件加速,能有效利用GPU

缺点

  • 只能操作DOM或XML对象的部分属性
  • 动画控制能力薄弱,不能逐帧定义动画状态
  • 支持的缓动函数有限(CSS3动画的贝塞尔曲线是一个标准3次方曲线)
  • 滥用硬件加速也会导致性能问题

CSS动画渲染优化原理

如上所说,渲染树构建完成后;浏览器要做的步骤:

reflow——》repaint——》composite

reflow和repaint

reflow和repaint都是耗费浏览器性能的操作,这两者尤以reflow为甚;因为每次reflow,浏览器都要重新计算每个元素的形状和位置。

由于reflow和repaint都是非常消耗性能的,我们的浏览器为此做了一些优化。浏览器会将reflow和repaint的操作积攒一批,然后做一次reflow。但是有些时候,你的代码会强制浏览器做多次reflow。例如:

var content = document.getElementById('content');
content.style.width = 700px;
var contentWidth = content.offsetWidth;
content.style.backgound = 'red';

以上第三行代码,需要浏览器reflow后;再获取值,所以会导致浏览器多做一次reflow。

下面是一些针对reflow和repaint的最佳实践:

  • 不要一条一条地修改dom的样式,尽量使用className一次修改。
  • 将dom离线后修改
    • 使用documentFragment对象在内存里操作dom。
    • 先把dom节点display:none;(会触发一次reflow)。然后做大量的修改后,再把它显示出来。
    • clone一个dom节点在内存里,修改之后;与在线的节点相替换。
  • 不要使用table布局,一个小改动会造成整个table的重新布局。
  • transform和opacity只会引起合成,不会引起布局和重绘。

从上述的最佳实践中你可能发现,动画优化一般都是尽可能地减少reflow、repaint的发生

composite

composite在GPU中进行

为了仅发生composite,我们做动画的css property必须满足以下三个条件:

  • 不影响文档流。
  • 不依赖文档流。
  • 不会造成重绘。

满足以上以上条件的css property只有transform和opacity。

但GPU加速会造成大量内存占用,使用不当会引起反效果。

GPU动画的优点和缺点

优点:

  • 每秒60帧,动画平滑、流畅。
  • 一个合适的动画工作在一个单独的线程,它不会被大量的js计算阻塞。
  • 3D“变换”是便宜的。

缺点:

  • 提升一个元素到复合层需要额外的重绘,有时这是慢的。(即我们得到的是一个全层重绘,而不是一个增量)
  • 绘图层必须传输到GPU。取决于层的数量和传输可能会非常缓慢。这可能让一个元素在中低档设备上闪烁。
  • 每个复合层都需要消耗额外的内存,过多的内存可能导致浏览器的崩溃。
  • 如果你不考虑隐式合成,而使用重绘;会导致额外的内存占用,并且浏览器崩溃的概率是非常高的。
  • 我们会有视觉假象,例如在Safari中的文本渲染,在某些情况下页面内容将消失或变形。
优化技巧
  1. 避免隐式合成
    • 保持动画的对象的z-index尽可能的高。理想的,这些元素应该是body元素的直接子元素。当然,这不是总可能的。所以你可以克隆一个元素,把它放在body元素下仅仅是为了做动画。
    • 将元素上设置will-change CSS属性,元素上有了这个属性,浏览器会提升这个元素成为一个复合层(不是总是)。这样动画就可以平滑的开始和结束。但是不要滥用这个属性,否则会大大增加内存消耗。
  2. 动画中只使用transform和opacity
  3. 减小复合层的尺寸

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions