纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

盒子端CSS动画性能提升 详解盒子端CSS动画性能提升

ChokCoco   2021-05-24 我要评论
想了解详解盒子端CSS动画性能提升的相关内容吗ChokCoco在本文为您仔细讲解盒子端CSS动画性能提升的相关知识和一些Code实例欢迎阅读和指正我们先划重点:css,动画,css,性能提升下面大家一起来学习吧

流畅动画的标准

理论上说FPS 越高动画会越流畅目前大多数设备的屏幕刷新率为 60 次/秒所以通常来讲 FPS 为 60frame/s 时动画效果最好也就是每帧的消耗时间为 16.67ms

直观感受不同帧率的体验

  • 帧率能够达到 50 ~ 60 FPS 的动画将会相当流畅让人倍感舒适
  • 帧率在 30 ~ 50 FPS 之间的动画因各人敏感程度不同舒适度因人而异
  • 帧率在 30 FPS 以下的动画让人感觉到明显的卡顿和不适感
  • 帧率波动很大的动画亦会使人感觉到卡顿

盒子端动画优化

在腾讯视频客厅盒子端Web 动画未进行优化之前一些复杂动画的帧率仅有 10 ~ 30 FPS卡顿感非常明显带来很不好的用户体验

而进行优化之后能将 10 ~ 30 FPS的动画优化至 30 ~ 60 FPS虽然不算优化到最完美但是当前盒子硬件的条件下已经算是非常大的进步

盒子端 Web 动画性能比较

首先先给出在盒子端不同类型的Web 动画的性能比较经过对比在盒子端 CSS 动画的性能要优于 Javascript 动画而在 CSS 动画里使用 GPU 硬件加速的动画性能要优于不使用硬件加速的性能

所以在盒子端实现一个 Web 动画优先级是:

GPU 硬件加速 CSS 动画 > 非硬件加速 CSS 动画 > Javascript 动画

动画性能上报分析

要有优化就必须得有数据做为支撑对比优化前后是否有提升而对于动画而言衡量一个动画的标准也就是 FPS 值

所以现在的关键是如何计算出每个动画运行时的帧率这里我使用的是requestAnimationFrame这个函数近似的得到动画运行时的帧率

考虑到盒子都是安卓系统且大多版本较低且硬件性能堪忧导致一是许多高级 API 无法使用二是这里只是近似得到动画帧率

原理是正常而言requestAnimationFrame这个方法在一秒内会执行 60 次也就是不掉帧的情况下假设动画在时间 A 开始执行在时间 B 结束耗时 x ms而中间requestAnimationFrame一共执行了 n 次则此段动画的帧率大致为:n / (B - A)

核心代码如下能近似计算每秒页面帧率以及我们额外记录一个allFrameCount用于记录 rAF 的执行次数用于计算每次动画的帧率 :

var rAF = function () {
    return (
        window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        function (callback) {
            window.setTimeout(callback, 1000 / 60);
        }
    );
}();
 
var frame = 0;
var allFrameCount = 0;
var lastTime = Date.now();
var lastFameTime = Date.now();
 
var loop = function () {
    var now = Date.now();
    var fs = (now - lastFameTime);
    var fps = Math.round(1000 / fs);
 
    lastFameTime = now;
    // 不置 0在动画的开头及结尾记录此值的差值算出 FPS
    allFrameCount++;
    frame++;
 
    if (now > 1000 + lastTime) {
        var fps = Math.round((frame * 1000) / (now - lastTime));
        // console.log('fps', fps); 每秒 FPS
        frame = 0;
        lastTime = now;
    };
 
    rAF(loop);
}

研究结论

所以我们的目标就是在使用 GPU 硬件加速的基础之上更深入的去优化 CSS 动画先给出最后的一个优化步骤方案:

1.精简 DOM 合理布局

2.使用 transform 代替 left、top减少使用耗性能样式

3.控制频繁动画的层级关系

4.考虑使用 will-change

5.使用 dev-tool 时间线 timeline 观察找出导致高耗时、掉帧的关键操作

下文会有每一步骤的具体分析解释

Web 每一帧的渲染

要想达到 60 FPS每帧的预算时间仅比 16 毫秒多一点 (1 秒/ 60 = 16.67 毫秒)但实际上浏览器有整理工作要做因此您的所有工作需要尽量在 10 毫秒内完成

而每一帧如果有必要我们能控制的部分也是像素至屏幕管道中的关键步骤如下:

完整的像素管道JS / CSS > 样式 > 布局 > 绘制 > 合成:

1.JavaScript一般来说我们会使用 JavaScript 来实现一些视觉变化的效果比如用 jQuery 的 animate 函数做一个动画、对一个数据集进行排序或者往页面里添加一些 DOM 元素等当然除了 JavaScript还有其他一些常用方法也可以实现视觉变化效果比如:CSS Animations、Transitions 和 Web Animation API

2.样式计算此过程是根据匹配选择器(例如 .headline 或 .nav > .nav__item)计算出哪些元素应用哪些 CSS 3. 规则的过程从中知道规则之后将应用规则并计算每个元素的最终样式

3.布局在知道对一个元素应用哪些规则之后浏览器即可开始计算它要占据的空间大小及其在屏幕的位置网页的布局模式意味着一个元素可能影响其他元素例如 <body> 元素的宽度一般会影响其子元素的宽度以及树中各处的节点因此对于浏览器来说布局过程是经常发生的

4.绘制绘制是填充像素的过程它涉及绘出文本、颜色、图像、边框和阴影基本上包括元素的每个可视部分绘制一般是在多个表面(通常称为层)上完成的

5.合成由于页面的各部分可能被绘制到多层由此它们需要按正确顺序绘制到屏幕上以便正确渲染页面对于与另一元素重叠的元素来说这点特别重要因为一个错误可能使一个元素错误地出现在另一个元素的上层

当然不一定每帧都总是会经过管道每个部分的处理我们的目标就是每一帧的动画对于上述的管道流程能避免则避免不能避免则最大限度优化

优化动画步骤

先给出一个步骤调优一个动画有一定的指导原则可以遵循一步一步深入动画:

1.精简 DOM 合理布局

这个没什么好说的如果可以精简 DOM 结构在任何时候都是对页面有帮助的

2.使用 transform 代替 left、top减少使用耗性能样式

现代浏览器在完成以下四种属性的动画时消耗成本较低:

  • position(位置):transform: translate(npx, npx)
  • scale(比例缩放):transform: scale(n)
  • rotation(旋转) :transform: rotate(ndeg)
  • opacity(透明度):opacity: 0...1

如果可以尽量只使用上述四种属性去控制动画

不同样式在消耗性能方面是不同的改变一些属性的开销比改变其他属性要多因此更可能使动画卡顿

例如与改变元素的文本颜色相比改变元素的box-shadow将需要开销大很多的绘图操作 改变元素的width可能比改变其transform要多一些开销如box-shadow属性从渲染角度来讲十分耗性能原因就是与其他样式相比它们的绘制代码执行时间过长

这就是说如果一个耗性能严重的样式经常需要重绘那么你就会遇到性能问题其次你要知道没有不变的事情在今天性能很差的样式可能明天就被优化并且浏览器之间也存在差异

开启 GPU 硬件加速

归根结底上述四种属性的动画消耗较低的原因是会开启了 GPU 硬件加速动画元素生成了自己的图形层(GraphicsLayer)

通常而言开启 GPU 加速的方法我们可以使用

will-change: transform

这会使声明了该样式属性的元素生成一个图形层告诉浏览器接下来该元素将会进行 transform 变换让浏览器提前做好准备

使用will-change并不一定会有性能的提升因为即使浏览器预料到会有这些更改依然会为这些属性运行布局和绘制流程所以提前告诉浏览器也并不会有太多性能上的提升这样做的好处是创建新的图层代价很高而等到需要时匆忙地创建不如一开始直接创建好

对于 Safari 及一些旧版本浏览器它们不能识别will-change则需要使用某种 translate 3D 进行 hack通常会使用

transform: translateZ(0)

所以正常而言在生产环境下我们可能需要使用如下代码开启硬件加速:

{
    will-change: transform;
    transform: translateZ(0);
}

3.控制频繁动画的层级关系

动画层级的控制的意思是尽量让需要进行 CSS 动画的元素的z-index保持在页面最上方避免浏览器创建不必要的图形层(GraphicsLayer)能够很好的提升渲染性能

OK这里又提到了图形层(GraphicsLayer)这是一个浏览器渲染原理相关的知识(WebKit/blink内核下)它能对动画进行加速但同时也存在相应的加速坑!

简单来说浏览器为了提升动画的性能为了在动画的每一帧的过程中不必每次都重新绘制整个页面在特定方式下可以触发生成一个合成层合成层拥有单独的 GraphicsLayer

需要进行动画的元素包含在这个合成层之下这样动画的每一帧只需要去重新绘制这个 Graphics Layer 即可从而达到提升动画性能的目的

那么一个元素什么时候会触发创建一个 Graphics Layer 层?从目前来说满足以下任意情况便会创建层:

  • 硬件加速的 iframe 元素(比如 iframe 嵌入的页面中有合成层)
  • 硬件加速的插件比如 flash 等等
  • 使用加速视频解码的<video>元素
  • 3D 或者 硬件加速的 2D Canvas 元素
  • 3D 或透视变换 (perspective、transform) 的 CSS 属性
  • 对自己的 opacity 做 CSS 动画或使用一个动画变换的元素
  • 拥有加速 CSS 过滤器的元素
  • 元素有一个包含复合层的后代节点(换句话说就是一个元素拥有一个子元素该子元素在自己的层里)
  • 元素有一个 z-index 较低且包含一个复合层的兄弟元素

本小点中说到的动画层级的控制原因就在于上面生成层的最后一条:

元素有一个 z-index 较低且包含一个复合层的兄弟元素

这里是存在坑的地方首先我们要明确两点:

1.我们希望我们的动画得到 GPU 硬件加速所以我们会利用类似transform: translateZ()这样的方式生成一个 Graphics Layer 层

2.Graphics Layer 虽好但不是越多越好每一帧的渲染内核都会去遍历计算当前所有的 Graphics Layer 并计算他们下一帧的重绘区域所以过量的 Graphics Layer 计算也会给渲染造成性能影响

记住这两点之后回到上面我们说的坑

假设我们有一个轮播图有一个 ul 列表结构如下:

<div class="container">
<div class="swiper">轮播图</div>
<ul class="list">
<li>列表li</li>
<li>列表li</li>
<li>列表li</li>
<li>列表li</li>
</ul>
</div>

假设给他们定义如下 CSS:

.swiper {
    position: static;
    animation: 10s move infinite;
}
 
.list {
    position: relative;
}
 
@keyframes move {
    100% {
        transform: translate3d(10px, 0, 0);
    }
}

由于给.swiper添加了translate3d(10px, 0, 0)动画所以它会生成一个 Graphics Layer如下图所示用开发者工具可以打开层的展示图形外的黄色边框即代表生成了一个独立的复合层拥有独立的 Graphics Layer 

但是!在上面的图中我们并没有给下面的list也添加任何能触发生成 Graphics Layer 的属性但是它也同样也有黄色的边框生成了一个独立的复合层

原因在于上面那条元素有一个 z-index 较低且包含一个复合层的兄弟元素我们并不希望list元素也生成 Graphics Layer 但是由于 CSS 层级定义原因下面的 list 的层级高于上面的 swiper所以它被动的也生成了一个 Graphics Layer 

使用 Chrome我们也可以观察到这种层级关系可以看到.list的层级高于.swiper:

所以下面我们修改一下 CSS 改成:

.swiper {
    position: relative;
    z-index: 100;
}
 
.list {
    position: relative;
}

这里我们明确使得.swiper的层级高于.list再打开开发者工具观察一下:

可以看到这一次.list元素已经没有了黄色外边框说明此时没有生成 Graphics Layer 再看看层级图:

此时层级关系才是我们希望看到的.list元素没有触发生成 Graphics Layer 而我们希望需要硬件加速的.swiper保持在最上方每次动画过程中只会独立重绘这部分的区域

总结

这个坑最早见于张云龙发布的这篇文章CSS3硬件加速也有坑这里还要总结补充的是:

GPU 硬件加速也会有坑当我们希望使用利用类似transform: translate3d()这样的方式开启 GPU 硬件加速一定要注意元素层级的关系尽量保持让需要进行 CSS 动画的元素的z-index保持在页面最上方

Graphics Layer 不是越多越好每一帧的渲染内核都会去遍历计算当前所有的 Graphics Layer 并计算他们下一帧的重绘区域所以过量的 Graphics Layer 计算也会给渲染造成性能影响

可以使用 Chrome 用上面介绍的两个工具对自己的页面生成的 Graphics Layer 和元素层级进行观察然后进行相应修改

上面观察页面层级的 chrome 工具非常吃内存?好像还是一个处于实验室的功能分析稍微大一点的页面容易直接卡死所以要多学会使用第一种观察黄色边框的方式查看页面生成的 Graphics Layer 这种方式

4. 使用 will-change 可以在元素属性真正发生变化之前提前做好对应准备

// 示例
.example {
    will-change: transform;
}

上面已经提到过 will-change 了

will-change 为 web 开发者提供了一种告知浏览器该元素会有哪些变化的方法这样浏览器可以在元素属性真正发生变化之前提前做好对应的优化准备工作 这种优化可以将一部分复杂的计算工作提前准备好使页面的反应更为快速灵敏

值得注意的是用好这个属性并不是很容易:

在一些低端盒子上will-change会导致很多小问题譬如会使图片模糊有的时候很容易适得其反所以使用的时候还需要多加测试

不要将 will-change 应用到太多元素上:浏览器已经尽力尝试去优化一切可以优化的东西了有一些更强力的优化如果与 will-change 结合在一起的话有可能会消耗很多机器资源如果过度使用的话可能导致页面响应缓慢或者消耗非常多的资源

有节制地使用:通常当元素恢复到初始状态时浏览器会丢弃掉之前做的优化工作但是如果直接在样式表中显式声明了 will-change 属性则表示目标元素可能会经常变化浏览器会将优化工作保存得比之前更久所以最佳实践是当元素变化之前和之后通过脚本来切换 will-change 的值

不要过早应用 will-change 优化:如果你的页面在性能方面没什么问题则不要添加 will-change 属性来榨取一丁点的速度 will-change 的设计初衷是作为最后的优化手段用来尝试解决现有的性能问题它不应该被用来预防性能问题过度使用 will-change 会导致生成大量图层进而导致大量的内存占用并会导致更复杂的渲染过程因为浏览器会试图准备可能存在的变化过程这会导致更严重的性能问题

给它足够的工作时间:这个属性是用来让页面开发者告知浏览器哪些属性可能会变化的然后浏览器可以选择在变化发生前提前去做一些优化工作所以给浏览器一点时间去真正做这些优化工作是非常重要的使用时需要尝试去找到一些方法提前一定时间获知元素可能发生的变化然后为它加上 will-change 属性

5. 使用 dev-tool 时间线 timeline 观察找出导致高耗时、掉帧的关键操作

1)对比屏幕快照观察每一帧包含的内容及具体的操作

2)找到掉帧的那一帧分析该帧内不同步骤的耗时占比进行有针对性的优化

3)观察是否存在内存泄漏

对于 timeline 的使用用法这里有个非常好的教程通俗易懂可以看看:

浏览器渲染优化 Udacity 课程

总结一下

对于盒子端 CSS 动画的性能很多方面仍处于探索中本文大量内容在之前文章已经出现过这里更多的是归纳总结提炼成可参照执行的流程

本文的优化方案研究同样适用于 PC Web 及移动 Web


相关文章

猜您喜欢

  • Idea中HTTP Client使用 详解Idea中HTTP Client请求测试工具的使用

    想了解详解Idea中HTTP Client请求测试工具的使用的相关内容吗hanxiaozhang2018在本文为您仔细讲解Idea中HTTP Client使用的相关知识和一些Code实例欢迎阅读和指正我们先划重点:Idea,HTTP,Client使用,Idea中HTTP,Client请求测试下面大家一起来学习吧..
  • .cuda()加载用时长 怎样解决.cuda()加载用时很长的问题

    想了解怎样解决.cuda()加载用时很长的问题的相关内容吗wang xiang在本文为您仔细讲解.cuda()加载用时长的相关知识和一些Code实例欢迎阅读和指正我们先划重点:.cuda(),加载用时长下面大家一起来学习吧..

网友评论

Copyright 2020 www.fresh-weather.com 【世纪下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式