你们好、这里就是用了大量动画去作我的主页、还有射击游戏的 yuki
。javascript
感受 css 的动画用的太多了,个人 MacBook 都要“罢工”了,回过头来,我就给你们总结一下,个人实验结果吧。(仍是好想用 css 动画css
这篇文章的目的大概就是,在网页里用 css 动画加一点复杂的动画,而后去作一些游戏或者艺术表现的时候,所有都用上 css 的 will-change 属性,怎么样才能让 GPU 渲染最合适。html
若是你要问 will-change 是什么?那能够看一下我放在这篇文章里的参考列表。vue
css-anime.firebaseapp.com/java
本次要验证的动画有下面几个点:css3
不知道你们有没有遇到过,须要一边作动画,还得一直加标签,而后还得一直显示,且不能从画面消失,这种很痛苦的状况。git
实验环境以下:github
以后会提一下 Safari 下的状况。 由于不一样的环境会有很大的差别,浏览器和操做系统不同的话,结果会有差别,我先在这里事先说明一下。web
译者注:下面连接所有都是*日文*的,标题我翻译了一下,日文 ok 的同窗能够点点看... 浏览器
这篇文章参考如下连接:
为了下手方便,我就先随便的写了一下,我把代码贴也上来了,你们看到代码应该也就就明白了。
花❀的话 html 部分大概就是这样的,为了轻松和我的兴趣,这里用了下 Vue,其实什么框架都是能够的。
Flower.vue
<div class="flower-root" :class="{animate: visible}" @animationend="onEndAnim">
<!-- 花瓣 -->
<div class="petal" v-for="(petal, index) in petals" :key="index" :style="{ transform: `rotate(${petal.r}deg)`, 'background-color': petal.col }">
</div>
<!-- 中间 -->
<div class="center"></div>
</div>
复制代码
花瓣是用 div 搭的,除了角度和颜色是在 template 里面写的,其它的都是在下面 <style> 标签里写的。开花的动画也在这里写了(也就是说,动画跟 Vue 和 javascirpt 没有关系,就只是用 css 写的而已)。
Flower.vue
<style lang="scss" scoped>
.flower-root {
position: absolute;
transform: rotate(0deg) scale(0);
animation: rotate 2s ease-out 0s 1 normal forwards;
}
.petal {
position: absolute;
width: 70px;
height: 20px;
top: -10px;
left: 0;
transform-origin: left center;
border-radius: 50px;
background-color: #ffb7aa;
}
.center {
position: absolute;
width: 30px;
height: 30px;
left: -15px;
top: -15px;
border-radius: 30px;
background-color: #ffe683;
}
// 一边旋转一遍变大
@keyframes rotate {
0% { transform: rotate(0deg) scale(0); }
100% { transform: rotate(360deg) scale(1); }
}
</style>
复制代码
写出来的花大概就是这种感受。
让这个 Flower 组件每隔必定时间,就往画面里加,而后画面的总体让它转起来。
先试试不用 will-change,跑一下动画,打开 Chrome 的 performance monitor 面板。
译者注:能够 f12 -> ctrl + shift + p 输入 rendering 打开 fps 面板,图片上左侧的 gpu 面板是 mac 系统自带的。
CPU 还挺给力的,还保持着 60 fps,哦哟,好像还不错哟。
500 个了。差很少 400 个左右的时候 CPU 已经到达瓶颈了,帧数一会儿就掉下来了,浏览器上了 GPU,可是帧数好像仍是很不稳定。
最后,平均帧数到了差很少 20fps,风扇一直转的大声...
全部的花都开完了,只剩下 1000 朵静止的花在旋转。到这一步,终于回复了 60fps。
可是不试试看怎么会知道呢?变动的地方就是在 style 里加上 will-change: transform。
Flower.vue
.flower-root {
position: absolute;
transform: rotate(0deg) scale(0);
animation: rotate 2s ease-out 0s 1 normal forwards;
will-change: transform; // 追加
}
复制代码
Let's start!
第 100 个,很是的流畅,CPU 负荷也很低。
500 个,开始有点挣扎了,GPU 就像吃了芥末同样,一会儿就窜起来了,CPU 也有点负荷了。
快到结尾了,CPU 和 GPU 都在疯狂的“惨叫”,performance 也是很危险的状态。
全部的开花的动画都结束了以后,负荷也不会降下来, 写了 will-change 的话,浏览器为了保证接下来的随时会开始的动画的性能,就算动画结束了,负荷也不会降低。
译者注:把 will-change 属性删除是指把 will-change 的指设置成默认的 auto,以后的翻译也都是如此。
实验 2 的问题是,开花的动画明明都已经结束了,可是 will-change 却存在着。所以,在实验 3,开花的动画结束后,就把 will-change 样式删除。
为了可以动态的设置 will-change 属性,因此把这个属性挪到 template 里了,而后加个变量去控制它(在 Vue 加了个 isMoving 变量)。监听 animationend 事件,在这个事件内,去改 isMoving 变量。
Flower.vue
<div class="flower-root" :style="{ 'will-change': isMoving ? 'transform' : 'auto', }" @animationend="onEndAnim">
...
复制代码
Flower.vue
private onEndAnim() {
this.isMoving = false
}
复制代码
检测到动画结束,只把 will-change 的值删除。
那么,start!
第 100 个,感受不错...
500 个,嗯?CPU 好吃力啊。帧数也差很少 300 个左右的时候就降下来了。由于动画结束了就把 will-change 给删了,GPU 负荷是轻了,可是 CPU 负担却重了。
到最后,差很少要“罢工”了。
全部的动画结束了以后,终于回复到 60fps 了。
好奇怪,结果并无那么明朗。 我只是在动画结束后立刻把 will-change 的值删了而已,到底发生了什么?
看了下 Chrome 的 performance 的状况,Update Layer Tree 很迷,隔一段时间执行一次。
这是 Chrome 内部的处理,我也不太知道具体是为何...
看 DevTools 的 Timeline 面板、理解浏览器的渲染机制(日文连接)
Update Layer Tree
GPU 更新着的执行处理的 layer
就是说,GPU 为了执行处理,把须要处理的元素放到 layer 上,把不须要处理的元素从 layer 删掉,而后从新构建。
此次试错的结果,如今的这个状况,Chrome 会有如下会倾向的点:
我没有看源码,这些也只是个人猜想。
在实验 3 中,动画结束,一个一个的去删 will-change 的值,效果会很是的糟糕。不知道为何 Chrome 要在这个点上这么的“努力”啊,我试试看有没有其它办法绕一下。
既然执一次一次去删 will-change 的话,会让 Update Layer Tree 产生负担,那么 100 个的话也是同样的吧。那么在攒必定数量以后一口气的去删掉的话会是怎么样呢?立刻来试试看。
准备好 Flower 队列
Flower.vue
const queueLimit = 100
const stopedFlowers: Flower[] = []
复制代码
动画结束后,加到队列里, 到 100 个了以后,设置 isMoving 的值,一口气删掉 will-change 的值。
Flower.vue
private onEndAnim() {
stopedFlowers.push(this)
if (stopedFlowers.length === queueLimit) {
stopedFlowers.forEach(fl => fl.isMoving = false)
stopedFlowers.length = 0
}
}
复制代码
感受有点像是在投机取巧,哈哈。实验开始!
第 100 个,这个时候动画才开始,will-change 所有都是带着的,也就是说,如今的这个状态跟实验 2 是同样的。
第 500 个,以 100 个为单位,删除 will-change,因此会隔一段时间,帧数会掉一下。
到最后这种状况会一直持续,虽然会有那么一瞬间帧数会卡一下,单总的来讲,负荷仍是很平衡的。
安全跑完,最后 100 个结束了以后,全部的元素都会删掉 will-change 的值。这时候,跟实验 1 和实验 3 的状态是同样的。
在 MacOS/iOS 的 Safari 跑了下,实验 3 的结果很是的流畅。
也就是说,若是不是 Chrome 的 bug 的话,难道是我使用的问题?由于没有看源码,因此也不太肯定。若是有知道的同窗,欢迎在评论区评论。
以前只是知道 will-change 会让浏览器启用 gpu 渲染,没想到这个使用多了,不必定就会爽了,使用 will-change 也是有不少须要注意的点。若是在须要大量使用动画的状况下,能够参考下这篇文章的作法,适当的去删掉 will-change 属性。