无线页面动画优化实例

无线页面本就分秒必争,更不用说当咱们在无线页面中使用动画的时候。不论是css动画仍是canvas动画,咱们都须要时刻当心着,而且有必要掌握页面性能的基本分析方法。css

既然咱们的目标是优化,那么就与浏览器的一些渲染和执行机制有关,更好的迎合浏览器的行为方式,才可让咱们的动画流畅而优美。html

没错,浏览器是老大,全听它的。html5

 

1、设备刷新率(帧率)

咱们想让页面变快,想让动画流畅,咱们须要先了解一下是什么在影响着咱们的感知。git

页面运行在设备的浏览器中,如今市面上的移动设备的刷新频率大可能是60次/秒(帧率)。因此给浏览器渲染每一帧的画面的时间应该是(1s/60=16.67ms)。github

但实际上,浏览器并非把功夫全花在为咱们渲染页面上,他还须要作一些额外的工做,好比渲染队列的管理和不一样线程的切换等等。因此,单纯的浏览器渲染工做留给咱们的时间大约也就是10ms左右,当咱们在每一帧所作的渲染操做大于这个时间的时候,比较直观的表现就是页面卡顿,动画卡顿。web

当咱们使用css animation完成动画时,这一点看起来没有那么重要,由于浏览器会为咱们handle一些事情。可是当咱们须要使用js好比canvas来实现流畅的逐帧动画时,须要牢记这个有限的时间,它很重要。chrome

2、浏览器的页面渲染流水线

咱们的代码是如何一步步的渲染成页面的呢?canvas

  • JavaScript。通常来讲,咱们使用JavaScript来实现一些页面逻辑,但偶尔咱们也可能会使用JavaScript来实现一些视觉变化的效果。好比用jQuery的animate函数作一个动画、或者往页面里添加一些DOM元素等。固然,如今更可能的是使用CSS Animations, Transitions和Web Animation API。
  • 计算样式(Style)。这个过程是经过样式文件中的CSS选择器,对每一个DOM元素匹配对应的CSS样式。
  • 布局(Layout)。上一步肯定了每一个DOM元素的样式规则,这一步就是具体计算每一个DOM元素最终在屏幕上显示的大小和位置。web页面中元素的布局是相对的,所以一个元素的布局发生变化,会联动地引起其余元素的布局发生变化。所以对于浏览器来讲,布局过程是常常发生的。
  • 绘制(Paint)。绘制,本质上就是填充像素的过程。包括绘制文字、颜色、图像、边框和阴影等,也就是一个DOM元素全部的可视效果。通常来讲,这个绘制过程是在多个层上完成的。
  • 渲染层合并(Composite)。由上一步可知,对页面中DOM元素的绘制是在多个层上进行的。在每一个层上完成绘制过程以后,浏览器会将全部层按照合理的顺序合并成一个图层,而后显示在屏幕上。对于有位置重叠的元素的页面,这个过程尤为重要,由于一旦图层的合并顺序出错,将会致使元素显示异常。  

看起来每一个页面都会经历这样的几个过程,然而咱们其实可使用一些技巧,帮助浏览器跳过某些步骤,而缩短他的工做时间。浏览器

1.五个步骤都消耗了时间框架

当咱们在js中改变了某个DOM元素的layout时,那么浏览器就会检查页面中的哪些元素须要从新布局,而后对页面激发一个reflow过程以完成页面的从新布局。被reflow的元素,接下来就必定会再次通过Paint和Composite这两个过程,以渲染出最新的页面。  

 

2.跳过layout这一步

当咱们只修改了一个DOM元素的paint only属性的时候,好比background-image/color/box-shadow等。这个时候不会触发layout,浏览器在完成样式的计算以后就会跳过layout的过程,就只Paint和Composite了。  

 

3.跳过layout和paint这两步

若是你修改一个非样式且非绘制的CSS属性,那么浏览器会在完成样式计算以后,跳过布局和绘制的过程,直接Composite。  

咱们尝试下使用transform动画来尽量的达到这种效果。

 

3、使用transform实现动画

咱们可能常常须要作一些动画,好比在作某些揭秘或者新手引导的效果时,会须要作一些将内容移入移出的操做。

固然可能第一个想到的就是 css transition 只要过渡一下 left 值或者 bottom 的值就能够了。效果或许很快就会实现,可是当咱们在一个页面频繁的作着这样的移入移出操做时,细心地咱们放在手机中(6P)看一看,动画并不会很流畅,尤为是在某些低端机型上。

咱们换用 transform 来实现相同的效果:

1 transition: left 2s ease-in-out;  ---> transition: transform 2s ease-in-out;  
2 left: xxx; ---> transform: translate3d(xxx, yyy, zzz); 

缘由在于:

  • 简单的说页面的绘制并非在单层的画面里完成的,这其中有渲染层合成层等概念。对 opacity 和 transform 应用了 CSS 动画的渲染层、有 3D 或者 perspective transform 的 CSS 属性的渲染层等知足一些条件的渲染层被称为合成层;
  • 合成层有本身的渲染上下文,而且交由 GPU 处理,比 CPU 要快;
  • 当页面须要重绘时,合成层的元素只会重绘本身层内的元素,而非整个页面;

优化事后再放在设备里查看,能够感觉到效果明显的提高。其实这里就作到了上面提到的,节省了layout和paint。

4、从css到canvas,使用requestAnimationFrame

如今css的动画愈来愈好用,也能知足愈来愈多的需求。但在某些复杂的需求中咱们可能仍是要求助于js。  

好比说我这里实现的一个半圆的动画:[半圆progress] [Source Code]。看起来使用css动画就彻底能够知足个人需求,可是当需求变化的时候,咱们也只能拥抱变化了。

 

**使用requestAnimationFrame**

[圆弧progress][Source Code] 这里用canvas实现了自定义弧度圆弧的增加动画。

这里咱们借助这个动画效果看一下是如何使用canvas和requestAnimationFrame来实现流畅的逐帧动画的。

window.requestAnimationFrame 是一个专门为动画而生的 web API 。它通知浏览器在页面重绘前执行你的回调函数。一般来讲被调用的频率是每秒60次。

假设咱们的页面上有一个动画效果,若是咱们想保证每一帧的顺利绘制,那么咱们就须要requestAnimationFrame来保证咱们的绘制时机了。

不少框架和示例代码都是用setTimeoutsetInterval来实现页面中的动画效果,好比jQuery中的animation。这种实现方式的问题是,你在setTimeoutsetInterval中指定的回调函数的执行时机是没法保证的。它将在这一帧动画的_某个时间点_被执行,极可能是在帧结束的时候。这就意味这咱们可能失去这一帧的信息。

 

**requestAnimationFrame的其余高能用法** 

根据requestAnimationFrame的特性,其实咱们还能够在不少别的想不到的地方来一显身手。

  • 动画:也是它的主要用途,它将咱们动画的执行时机和执行频率交由浏览器决定,以获得更好的性能;
  • 函数节流:requestAnimationFrame 的执行频率(一帧)是16.67ms,利用这一个特征就能够作到函数节流,避免高频事件在一帧内作多余的无用功的函数执行,例:
  •  1 var $box = $('#J_Test'),
     2       $point = $box.find('b');
     3 $box.on('mouseenter',function(e){
     4   requestAnimationFrame(function(){
     5       $point.css({
     6           top : e.pageY,
     7           left : e.pageX
     8       })
     9   });
    11 });
  • 分帧初始化:一样利用一帧的执行时间将模块的初始化或渲染函数分散到不一样的帧中来执行,这样每一个模块都有16.67ms的执行时间,而不是一股脑的堆在那里等着执行;
 1  var rAF = window.requestAnimationFrame ||  window.webkitRequestAnimationFrame || 
 2         function(c) {
 3             setTimeout(c, 1 / 60 * 1000);
 4         };
 5 
 6     function render() {
 7        self.$container.html(itemHtml);
 8        self.$container.find('.J_LazyLoad').lazyload();
 9     }
10 
11     rAF(render);

 

5、分析你的无线页面

咱们仍是借助这个例子,[圆弧progress][Source Code] 简单的看下如何分析无线页面的性能。

这里的实现思路是这样的:

1 - 肯定圆弧的起始弧度(0.75PI)和终止弧度(根据当前分值占上限分值的比例计算,最大为2.25PI); 
2 - 随着时间的增加逐帧绘制终点位置 requestAnimationFrame(draw);
3 - 根据每一帧的终点位置的 cos 和 sin 值获得跟随的圆圈坐标并绘制;

但固然,实现完成只是走了第一步,咱们来借助Chrome Timeline来分析一下这个简单的页面。

 

  1. 看一下帧率,在进度动画进行的时候,看起来帧率不错,没有产生掉帧的现象,说明每一帧的耗时都还ok,个人动画基本不会卡顿;
  2. 在函数的执行和调用那一栏中,可能有问题的部分右上角会被标红,还能够查看可能存在问题的细节;这里提示我页面强制重排了,仔细观察下面的 Bottom-up tab 中能够定位到具体的代码。

使用Timeline就能够看到页面的几种指标,帧率,js执行等等。就能够针对出现问题的帧下手优化。

在分析页面性能的时候,严重推荐阅读:[https://developer.chrome.com/devtools/docs/timeline] .timeline的详细使用说明,它真的很强大,能帮助咱们分析到页面的各个方面的问题。

相关文章
相关标签/搜索