前端动画性能优化方案
几种实现动画效果的方式:
准备知识
GPU是图形处理器,专门处理和绘制图形相关的硬件。GPU是专为执行复杂的数学和几何计算而设计的,使得CPU从图形处理的任务中解放出来,可以执行其他更多的系统任务
所谓硬件加速,就是在计算机中把计算量非常大的工作分配给专门的硬件来处理,减轻CPU的工作量
CSS的动画、变形、渐变并不会自动触发GPU加速,而是使用浏览器稍慢的软件渲染引擎。在transition
、transform
和animation
的世界里,应该卸载进程到GPU以加速速度。只有3D变形会有自己的layer,而2D变形则不会
一、transition:height ;
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<style type="text/css">
.d1 {
background: palegreen;
width: 100px;
height: 100px;
transition:height 1s ;
}
.d1:hover {
height: 200px;
}
</style>
<body>
<div class="d1"></div>
</body>
</html>
在动画的每一帧中,浏览器都要执行布局、 绘制、 以及将新的位图提交给 GPU
浏览器需要做大量工作的原因在于每一帧中元素的内容都在不断改变。改变一个元素的高度可能导致需要同步改变它的子元素的大小,所以浏览器必须重新计算布局。布局完成后,主线程又必须重新生成该元素的位图。
二、transform属性:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<style type="text/css">
.d1 {
width: 100px;
height: 100px;
background: palegreen;
transform: scale(0.5);
transition: transform 1s linear;
}
.d1:hover {
transform: scale(1.0);
}
</style>
<body>
<div class="d1"></div>
</body>
</html>
CSS 的transform属性不会更改元素或它周围的元素的布局。transform属性会对元素的整体产生影响,它会对整个元素进行缩放、旋转、移动处理。
使用 transform,浏览器只需要一次生成这个元素的位图,并在动画开始的时候将它提交给 GPU 去处理 。之后,浏览器不需要再做任何布局、 绘制以及提交位图的操作。从而,浏览器可以充分利用 GPU 的特长去快速地将位图绘制在不同的位置、执行旋转或缩放处理。
三、通过GPU硬件加速:
为动画DOM元素添加CSS3样式:
-webkit-transform:transition3d(0,0,0)或-webkit-transform:translateZ(0);,
这两个属性都会开启GPU硬件加速模式,从而让浏览器在渲染动画时从CPU转向GPU
but 使用translateZ()
或translate3d()
方法为元素添加没有变化的3D变形,骗取浏览器触发硬件加速。但是,代价是这种情况通过向它自己的层叠加元素,占用了RAM和GPU的存储空间,且无法确定空间释放时间.
四、设置 will-chahge 属性
will-change
功能: 提前通知浏览器元素将要做什么动画,让浏览器提前准备合适的优化设置
值: auto | <animateable-feature>
初始值: auto
应用于: 所有元素
继承性: 无
兼容性: IE13+、chrome49+、safari9.1+、IOS9.3+、Android52+
auto表示没有特别指定哪些属性会变化,浏览器需要自己去猜,然后使用浏览器经常使用的一些常规方法优化
<animateable-feature>
可以是以下值:
scroll-position
表示开发者希望在不久后改变滚动条的位置或者使之产生动画
contents
表示开发者希望在不久后改变元素内容中的某些东西,或者使它们产生动画
<custom-ident>
表示开发者希望在不久后改变指定的属性名或者使之产生动画。如果属性名是简写,则代表所有与之对应的简写或者全写的属性
使用
【使用hover】
不要像下面这样直接写在默认状态中,因为will-change会一直挂着:
.will-change {
will-change: transform;
transition: transform 0.3s;
}
.will-change:hover {
transform: scale(1.5);
}
可以让父元素hover的时候,声明will-change,这样,移出的时候就会自动remove,触发的范围基本上是有效元素范围
.will-change-parent:hover .will-change {
will-change: transform;
}
.will-change {
transition: transform 0.3s;
}
.will-change:hover {
transform: scale(1.5);
}
【使用javascript脚本】
.sidebar {
will-change: transform;
}
以上示例在样式表中直接添加了will-change属性,会导致浏览器将对应的优化工作一直保存在内存中,这其实是不必要的。下面展示如何使用脚本正确地应用will-change
属性
var el = document.getElementById('element');
// 当鼠标移动到该元素上时给该元素设置 will-change 属性
el.addEventListener('mouseenter', hintBrowser);
// 当 CSS 动画结束后清除 will-change 属性
el.addEventListener('animationEnd', removeHint);
function hintBrowser() {
// 填写在CSS动画中发生改变的CSS属性名
this.style.willChange = 'transform, opacity';
}
function removeHint() {
this.style.willChange = 'auto';
}
【直接使用】
但是,如果某个应用在按下键盘的时候会翻页,比如相册或者幻灯片一类,它的页面很大很复杂,此时在样式表中写上will-change是合适的。这会使浏览器提前准备好过渡动画,当键盘按下的时候就能即看到灵活轻快的动画
.slide {
will-change: transform;
}
注意事项
1、不要将will-change应用到太多元素上:浏览器已经尽力尝试去优化一切可以优化的东西了。有一些更强力的优化,如果与will-change结合在一起的话,有可能会消耗很多机器资源,如果过度使用的话,可能导致页面响应缓慢或者消耗非常多的资源
2、有节制地使用:通常,当元素恢复到初始状态时,浏览器会丢弃掉之前做的优化工作。但是如果直接在样式表中显式声明了will-change属性,则表示目标元素可能会经常变化,浏览器会将优化工作保存得比之前更久。所以最佳实践是当元素变化之前和之后通过脚本来切换will-change的值
3、不要过早应用will-change优化:如果页面在性能方面没什么问题,则不要添加will-change属性来榨取一丁点的速度。will-change的设计初衷是作为最后的优化手段,用来尝试解决现有的性能问题。它不应该被用来预防性能问题。过度使用will-change会导致大量的内存占用,并会导致更复杂的渲染过程,因为浏览器会试图准备可能存在的变化过程。这会导致更严重的性能问题
4、给它足够的工作时间:这个属性是用来让页面开发者告知浏览器哪些属性可能会变化的。然后浏览器可以选择在变化发生前提前去做一些优化工作。所以给浏览器一点时间去真正做这些优化工作是非常重要的。使用时需要尝试去找到一些方法提前一定时间获知元素可能发生的变化,然后为它加上will-change属性