js 图片缩放不超出父级元素范围_为什么 CSS 动画比 JS 高效?

显示器如何显示图像?

每个显示器都有固定的刷新频率,通常是 60HZ,即每秒更新 60 张图片。更新的图片都来自于显卡中一个叫前缓冲区的地方。显示器所做的任务就是每秒固定读取 60 次前缓冲区中的图像并将其显示到显示器上。

显卡用来干什么?

显卡负责合成新图像并将其保存到后缓冲区,一旦显卡把合成好的图像写到后缓冲区,系统就会让后缓冲区与前缓冲区互换,以此来保证显示器读取到的是新图像。

通常情况下,显卡更新频率与显示器刷新频率一致。但是在复杂场景中,显卡处理图片的速度会变慢,造成视觉上的卡顿。

帧与帧率

当通过滚动条滚动页面或者通过手势缩放页面时,屏幕上会有动画效果。之所以会有动画效果,是因为在滚动与缩放过程中,渲染引擎会通过渲染流水线生成新的图片,并发送到显卡的后缓冲区。

我们把渲染流水线生成的每一副图片称为一帧,把每秒更新多少帧称为帧率。比如,滚动过程中 1s 更新 60 帧,那么帧率就为 60Hz 或者 60FPS.

要解决卡顿问题,就要解决每帧生成时间过久的问题。为此 Chrome 引入分层与合成机制。

如何生成一帧图像?

三种方式:重排、重绘、合成。

上面三种渲染路径不同,通常渲染路径越长,生成图像花费的时间就越多。

Chrome 合成技术可以用三个词概括:分层、分块、合成。

分层与合成

为什么要引入分层与合成机制?

页面要实现一些复杂的动画效果,从布局树直接生成目标图片的话,每次页面的微小变化都会触发重排与重绘,严重影响页面渲染效率。

为了提升每帧的渲染效率,Chrome 引入了分层与合成机制。

如何理解分层与合成机制?

你可以把一张网页想成是由很多图片叠加在一起的,每个图片就对应一个图层(类似于 PhotoShop 中的图层,可以设置透明度、边框、阴影等),Chrome 的合成器最终将这些图层合成了用于显示页面的图片。

此过程中,将素材分解为多个图层的操作就叫分层,将图层合并的过程就叫合成

一个页面被分为两个层,当到下一帧渲染时,上一帧可能要实现某些变换(平移、旋转、缩放等),这时合成器只需将这两个层进行相应的变化,合成时间非常短。

Chorme 是怎么实现分层与合成机制的?

生成布局树后,渲染引擎会根据布局树的特点将其转换为层树(分层),层树中每个节点都对应着一个图层,绘制阶段就依赖于层树中的节点。绘制阶段并不是真正的绘制图片,而是将绘制指令组合成一个列表。具体见从输入 URL 到页面展示,中间发生了什么分层部分。

合成操作是在合成线程上完成的,这意味着在执行合成操作时,是不会影响到主线程的。

这也是为什么即使主线程卡住了,CSS 动画依然能执行。

分块

如果说分层是从宏观上提升了渲染效率,那么分块则是从微观层面提升了渲染效率。

通常情况下,页面内容远大于屏幕大小。如果等所有图层都生成完毕再合成,会让合成图片的时间变得更久。

因此合成线程会将每个图层分为大小固定的图块,然后优先绘制靠近视口的图块,这样就可以加速页面显示速度。不过,有时即使只绘制优先级高的图块,也要耗费不少时间,因为中间涉及到纹理上传,从计算机内存上传到 GPU 内存的操作会比较慢。

为了解决这个问题,Chrome 在首次合成图块的时候使用一个低分辨率的图片。

分辨率减少一半,纹理就减少了四分之三。首次展示页面时,展示低分辨率图片,然后合成器继续绘制正常比例的页面内容,当绘制完成后,再替换掉当前显示的低分辨率内容。

利用分层技术优化代码

如果要对某个元素做几何形状变化、透明度变换或者缩放,可以使用 will-change 告诉渲染引擎,如下:

.box { will-change: transform, opacity; }

will-change 会提前告诉渲染引擎 box 元素要做几何变换和透明度变换操作,这是渲染引擎会将该元素单独实现一层,等变换发生时,渲染引擎会通过合成线程直接处理变换,此变换不涉及主线程,故效率高。这就是 CSS 动画比 JS 动画高效的原因。

注意点:will-change 会让渲染引擎为该元素准备独立层,占用的内存也会大大增加,因为从层树开始,后续每个阶段都会多一个层结构,都需要额外内存。

合成线程里完成哪些操作?

能直接在合成线程中完成的任务都不会改变图层的内容,如文字信息的改变,布局的改变,颜色的改变,统统不会涉及,涉及到这些内容的变化就要牵涉到重排或者重绘了。

能直接在合成线程中实现的是整个图层的几何变换,透明度变换,阴影等,这些变换都不会影响到图层的内容。

比如滚动页面的时候,整个页面内容没有变化,这时候做的其实是对图层做上下移动,这种操作直接在合成线程里面就可以完成了。

再比如旋转操作,如果样式里面使用了 will-change ,那么这些 box 元素都会生成单独的一层,那么在旋转操作时,只要在合成线程将这些 box 图层整体旋转到设置的角度,再拿旋转后的 box 图层和背景图层合成一张新图片,这个图片就是最终输出的一帧,整个过程都是在合成线程中实现的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值