Code前端首页关于Code前端联系我们

为什么transform比较圆滑? CSS3动画粘贴性能优化解决方案

terry 2年前 (2023-09-27) 阅读数 81 #数据结构与算法
为什么transform更加平滑?CSS3动画卡顿性能优化解决方案

最近一直在开发小程序。和vue一样,它们都有生命周期。

onLoad 监控页面加载 onReady 监控初始页面渲染完成 onShow 监控页面显示

这是什么意思?

所以这又碰到了我的知识盲点,不过尽管有一些绊脚石,项目也差不多完成了,但是我在渲染 CSS3 动画时遇到了性能问题,所以我被迫返回并从渲染网页浏览器。从流程入手,找到动画卡顿的核心。

在浏览器中渲染网页的过程如下:

使用 HTML 创建文档对象模型 (DOM) 使用 CSS 创建 CSS 对象模型 (CSSOM) 基于 DOM 运行脚本 (Scripts) CSSOM 通过合并 DOM 和 CSSOM,创建渲染树(Render Tree) 使用渲染树的布局(Layout)所有元素来渲染(Painting)所有元素

可以将Alon前端性能优化和 Android 开发结合起来页面显示选项。

Android开发者选项页面查看布局

如何判断移动应用是原生、WebView还是混合?简单来说,该应用程序的大部分内容是白色的,没有红线标记,但上面有按钮和图像。等待时,它是一个 webview,即通过伪浏览器请求的数据。网络断开时,打开应用程序时应用程序中不显示任何内容 为什么transform更加平滑?CSS3动画卡顿性能优化解决方案

onLoad 监控页面加载 界面渲染后,即通过。当json中的配置项生成原生界面时,webview部分开始渲染,页面仅被调用一次。 onReady 监听页面初始渲染完成情况 该页面只会被调用一次,表明页面已准备就绪,可以与视图层交互。 onShow 监控页面的显示,并在每次打开页面时调用该函数。

我们的动画应该放在哪里?

应该放在 onShow 中,因为每次打开时我都会看到动画。

为什么会结冰?

有一个前提需要提一下。所有前端开发人员都知道浏览器运行在单线程上。但是,我们需要澄清以下术语:单丝、短纤维和合成纤维。

虽然说浏览器是单线程运行js的(注意,运行并不是说浏览器只有一个线程,而是正在运行),但实际上浏览器有两个重要的执行线程,这2个线程协同工作渲染网页:主线程和创建线程。

一般来说,主线程负责:运行JavaScript;计算 HTML 元素的 CSS 样式;页面布局;将元素绘制到一个或多个位图中;并将这些位图传递给合成线程。

相应地,合成线程负责:通过GPU将位图绘制到屏幕上;通知主线程更新页面中可见或将变得可见的部分的位图;计算页面的哪一部分是可见的;计算页面滚动时哪些部分变得可见;滚动页面时,将元素移动到可见区域的相应位置。

那么为什么动画会卡住呢?

原因是主纤维与合成纤维的布局不相称。

我们来详细说说规划不合理的原因。

使用高度、宽度、边距和填充作为过渡值会导致浏览器主线程的工作负载过重。例如,当从 margin-left: -20px 渲染到 margin-left:0 时,主线程必须计算样式 margin-left:-19px 、 margin-left:-18px 到 margin-left:0 ,并且每次主线程计算样式,合成过程需要在GPU上绘制然后在屏幕上渲染,前后总共20次。次主线程的渲染,20个复合线程渲染,20+20次,共40次计算。

在浏览器中可以看到网页渲染过程中的主线程渲染过程:

使用 HTML 创建文档对象模型(DOM) 使用 CSS 创建 CSS 对象模型(CSSOM) 运行基于 DOM 和 CSSOM 的脚本(scripts)) 合并 DOM 和 CSSOM,创建渲染树(Render Tree) 利用渲染树的布局(Layout)来渲染(Painting)所有元素

也就是说主线程每次都必须运行脚本、渲染树、布局和绘画四个阶段的计算。

而如果使用transform,例如transform:translate(-20px,0)到transform:translate(0,0),主线程只需要对transform做translate:translate(-20px,0):翻译(0)一次,0)然后合成线程立即将-20px转换为0px。在这种情况下,总计算量为1+20。

有人可能会说这个只改进了19次。有什么好的性能提升吗?

假设一次 10 毫秒。

这减少了约190ms的时间消耗。

有人会说,辣子鸡,才190ms,无所谓。

如果左边距一次从-200px到0.10ms怎么办,10ms*199≈2s。

也有人说辣子鸡只有2个,没关系。

你忘记了单线程吗?

如果一个网页有3个动画,3*2s=6s,也就是6s的性能提升。由于这些都是推测,其真实性暂时不予考虑。在本文后面,我对 chrome devtools 性能进行了实验。

要知道,在当今“客户至上”的世界里,良好的用户体验是所有产品都必须遵循的规则。无论是作为开发人员还是产品经理,追求性能最大化是我们创造优秀产品所需要的。基本素质。

也许看完我有些不专业的分析,你对两种性能不同的动画方案的主线程、合成线程及其工作流程还不太了解。大家可以阅读翻译后的博客(英文原版链接已过期):深入理解浏览器中的CSS动画和转场性能问题

这篇文章完美的描述了浏览器主线程和合成线程的区别,并给出了示例 2 的高度从 100px 变为 200px。两种动画方案的比较以及对主线程和合成线程整个工作流程的非常详细的解释。我真诚地建议您仔细阅读。

我们回过头来总结一下css3动画卡住的解决办法:在使用css3转场做动画效果时,优先考虑transform,尽量不要使用高度、宽度、边框和内边距。

transform为我们提供了缩放、折叠、旋转等丰富的API,但使用时要考虑兼容性。但实际上,对于大多数CSS3来说,移动端有更好的支持,桌面端需要特别关注。


附录:为了增加这篇文章的说服力,我回家做了一个实验。代码如下。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>Page Title</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    .margin-transition{
      /* margin-left: 0; */
      background: rgba(0,0,255,0.3);
      transition: margin-left 1s;
    }
    .transform-transition{
      /* transform: translate(0,0); */
      background: rgba(0,255,0,0.3);
      transition: transform 1s;
    }
    .common{
      height: 300px;
      width: 300px;
    }
  </style>
</head>
<body>
  <div class="margin-transition common" id="marginTransition">
    <p>transition:margin-left 1s</p>
  </div>
  <div class="transform-transition common" id="transformTransition">
      <p>transition:tranform 1s</p>
  </div>
  <button id="control">见证奇迹</button>
  <script>
      var btn = document.getElementById('control');
      var marginTransition = document.getElementById('marginTransition');
      var transformTransition = document.getElementById('transformTransition');
      btn.addEventListener("click",function(){
        console.log(marginTransition.style,transformTransition.style)
        marginTransition.style.marginLeft = "500px";
        transformTransition.style.transform = "translate(500px,0)"
      })
  </script>  
</body>
</html>
复制代码

我主要会使用chrome devtools性能工具来比较两个工具的性能差异。首先我们看一下边框动画,动态调整DOM节点的左边框值,从0到500像素;。

transition: margin-left 1s;
复制代码
为什么transform更加平滑?CSS3动画卡顿性能优化解决方案为什么transform更加平滑?CSS3动画卡顿性能优化解决方案为什么transform更加平滑?CSS3动画卡顿性能优化解决方案

我们再看一下transform的动画,动态调整transform的DOM节点值从translate(0,0)到translate(500px,0)。

transition: transform 1s;
复制代码
为什么transform更加平滑?CSS3动画卡顿性能优化解决方案为什么transform更加平滑?CSS3动画卡顿性能优化解决方案为什么transform更加平滑?CSS3动画卡顿性能优化解决方案

图片可能不能很好地说明性能差异,所以让我们制作一个耗时的比较表,这将使我们的计算更加容易。

耗时保证金transform
夏天3518ms2286ms‶❙2286ms‶‶8ms 2.9ms
渲染22 .5 ms6.9 ms
绘画9.7 ms1.6 ms
其他39.3 ms❙ CPU 或 GPU进行一些处理)3444.4ms2249.8 ms
GPU使用量4.1MB1.7MB在CSS中转换效果时,我们可以通过3个差异表参数删除transform的功率差异和清晰余量。
关键性能参数margintransform
实际动画时间(总时间减去空闲时间)♝2mstransform动画时间约为边缘动画所需时间的0.49倍性能优化50%。

由于我不太清楚Other具体做了什么事情,所以这里的实际动画时间也可以从Other中的时间减去。下表显示了减去后的数据。

关键性能参数margintransform
实际动画时间(总时间减去其他时间和空闲时间)❙34.3ms‷‷111,transform动画耗时约为0.32-多边缘动画性能优化接近70%。

也就是说,无论我们是否减去Other时间,我们使用transform实现动画的方式都比边缘动画要快。

不准确地得出一个小结论:transform的表现比差值好50%~70%

即使性能有 50% 到 70% 的提升,也需要注意硬件的差异。如果硬件良好,则可能不会发现滞后或其他性能问题。例如,在开发小程序的过程中,模拟器被放置在桌面端,因此它的硬件性能更好,例如CPU和GPU。但一旦运行在ios、android等移动端,可能会出现性能问题。这是因为移动端的硬件条件比PC端差。

所以性能问题一直存在,只是硬件的差异会造成不同程度的性能影响。

那么我们再回去总结一下css3动画卡住的解决办法: 在使用css3过渡做动画效果时,优先选择transform,尽量不要使用height、width、border和padding。

2018年11月28日更新为什么transform更圆滑?

作曲家的优点是他的作品与主线程无关。 Composer 线程不必等待样式计算或 JS 执行。这就是为什么与composer相关的动画是最流畅的。如果动画涉及到布局或者绘图调整,就会涉及到主线程的重新计算,自然会慢很多。

引用infoQ一篇好文章:史上最全!图形浏览器

结合我们博客的上下文解释如下: 使用css3翻译做动画效果时,transform实现的动画与composer线程相关,不需要等待对于主线程式计算或者JS执行,计算速度非常快;使用height、width、border、padding时,调整布局和绘制,主线程需要重新计算样式和运行JS,计算速度自然就慢。

作者:趁你还年轻233
来源:掘金

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门