前端性能优化-CSS的性能优化:--transform与position的区别、硬件加速工作原理及注意事项

上个星期去baidu二面面试,第一题就有问到这样问题: transform与position:absolute 有什么区别? 回家后查资料发现这道题目其实不简单啊,涉及到重排、重绘、硬件加速等网页优化的知识。

⼀、问题背景

  过去⼏年,我们常常会听说硬件加速给移动端带来了巨⼤的体验提升,但是即使对于很多经验丰富的开发者来说,恐怕对其背后的⼯作
原理也是模棱两可,更不要合理地将其运⽤到⽹页的动画效果中了。
1、position + top/left 的效果
  下⾯让我们来看⼀个动画效果,在该动画中包含了⼏个堆叠在⼀起的球并让它们沿相同路径移动。最简单的⽅式就是实时调整它们的
left 和 top 属性,使⽤ css 动画实现。

复制代码
<style>
    html,
    body {
        width: 100%;
        height: 100%;
    }
    
    .ball-running {
        animation: run-around 4s infinite;
        width: 100px;
        height: 100px;
        background-color: red;
        position: absolute;
    }
    
    @keyframes run-around {
        0%: {
            top: 0;
            left: 0;
        }
        25% {
            top: 0;
            left: 200px;
        }
        50% {
            top: 200px;
            left: 200px;
        }
        75% {
            top: 200px;
            left: 0;
        }
    }
    
</style>
<body>
    <div class="ball-running"></div>
 
</body>
复制代码

 

在运⾏的时候,即使是在电脑浏览器上也会隐约觉得动画的运⾏并不流畅,动画有些停顿的感觉,更不要提在移动端达到 60fps 的流畅
效果了。这是因为top和left的改变会触发浏览器的 reflow 和 repaint ,整个动画过程都在不断触发浏览器的重新渲染,这个过程是很影响性能的。

 

 

 

 

 


2、transform 的效果
  为了解决这个问题,我们使⽤ transform 中的 translate() 来替换 top 和 left ,重写⼀下这个动画效果。

复制代码
<style>
    html,
    body {
        width: 100%;
        height: 100%;
    }
    
    .ball-running {
        animation: run-around2 4s infinite;
        width: 100px;
        height: 100px;
        background-color: red;
        position: absolute;
    }
    
 
    @keyframes run-around2 {
        0%: {
            transform: translate(0, 0);
        }
        25% {
            transform: translate(200px, 0);
        }
        50% {
            transform: translate(200px, 200px);
        }
        75% {
            transform: translate(0, 200px);
        }
    }
</style>
 
<body>
    <div class="ball-running"></div>
</body>
复制代码

 


这时候发现整个动画效果流畅了很多,在动画移动的过程中也没有发⽣repaint和reflow。
下面是chrome 浏览器performance中的监测到的数据。以及rendering面板。

 

 

 

 

 

 

那么,为什么 transform 没有触发 repaint 呢?原因就是,transform 动画由GPU控制,支持硬件加速。并不需要软件⽅⾯的渲染。

看完以上两个例子,那么我们就要入正题了。

⼆、硬件加速⼯作原理

  浏览器接收到页⾯⽂档后,会将⽂档中的标记语⾔解析为DOM树,DOM树和CSS结合后形成浏览器构建页⾯的渲染树,渲染树中包含
了⼤量的渲染元素,每⼀个渲染元素会被分到⼀个图层中,每个图层⼜会被加载到GPU形成渲染纹理,⽽图层在GPU中 transform 是不会触
发 repaint 的,这⼀点⾮常类似3D绘图功能,最终这些使⽤transform的图层都会使⽤独⽴的合成器进程进⾏处理。
  在我们的⽰例中,CSS transform 创建了⼀个新的复合图层,可以被GPU直接⽤来执⾏ transform 操作。在chrome开发者⼯具中开
启“show layer borders”选项后,每个复合图层就会显⽰⼀条黄⾊的边界。⽰例中的球就处于⼀个独⽴的复合图层,移动时的变化也是独⽴
的。
  此时,你也许会问:浏览器什么时候会创建⼀个独⽴的复合图层呢?事实上⼀般是在以下⼏种情况下:
(1)3D 或者 CSS transform
(2)video或canvas标签
(3)CSS filters
(4)元素覆盖时,⽐如使⽤了 z-index 属性
  等⼀下,上⾯的⽰例使⽤的是 2D transition ⽽不是 3D 的 transforms 啊?这个说法没错,所以在timeline中我们可以看到:动画开始和结束的时候发⽣了两次 repaint 操作。
3D 和 2D transform 的区别就在于,浏览器在页⾯渲染前为3D动画创建独⽴的复合图层,⽽在运⾏期间为2D动画创建。
  动画开始时,⽣成新的复合图层并加载为GPU的纹理⽤于初始化 repaint,然后由GPU的复合器操纵整个动画的执⾏,最后当动画结束
时,再次执⾏ repaint 操作删除复合图层。

三、使⽤ GPU 渲染元素
1、能触发GPU渲染的属性
  并不是所有的CSS属性都能触发GPU的硬件加速,实际上只有少数属性可以,⽐如下⾯的这些:
(1)transform
(2)opacity
(3)filter
2、强制使⽤GPU渲染
  为了避免 2D transform 动画在开始和结束时发⽣的 repaint 操作,我们可以硬编码⼀些样式来解决这个问题:

.exam1{
    transform: translateZ(0);
}
.exam2{
    transform: rotateZ(360deg);
}

 


这段代码的作⽤就是让浏览器执⾏ 3D transform,浏览器通过该样式创建了⼀个独⽴图层,图层中的动画则有GPU进⾏预处理并且触发
了硬件加速。
3、使⽤硬件加速需要注意的事项
  使⽤硬件加速并不是⼗全⼗美的事情,⽐如:
(1)内存。如果GPU加载了⼤量的纹理,那么很容易就会发⽣内存问题,这⼀点在移动端浏览器上尤为明显,所以,⼀定要牢记不要让页
⾯的每个元素都使⽤硬件加速。
(2)使⽤GPU渲染会影响字体的抗锯齿效果。这是因为GPU和CPU具有不同的渲染机制,即使最终硬件加速停⽌了,⽂本还是会在动画期
间显⽰得很模糊。
4、will-change
  浏览器还提出了⼀个 will-change 属性,该属性允许开发者告知浏览器哪⼀个属性即将发⽣变化,从⽽为浏览器对该属性进⾏优化提供
了时间。下⾯是⼀个使⽤ will-change 的⽰例

.exam3{
will-change: transform;
}
缺点在于其兼容性不⼤好。

总结:
可以使用GPU加速的CSS3属性

CSS transform
CSS opacity
CSS filter
1、transform 会使⽤ GPU 硬件加速,性能更好;position + top/left 会触发⼤量的重绘和回流,性能影响较⼤。
2、硬件加速的⼯作原理是创建⼀个新的复合图层,然后使⽤合成线程进⾏渲染。
3、3D 动画与 2D 动画的区别;2D动画会在动画开始和动画结束时触发2次重新渲染。
4、使⽤GPU可以优化动画效果,但是不要滥⽤,会有内存问题。
5、理解强制触发硬件加速的 transform 技巧,使⽤对GPU友好的CSS属性。

既然transform这个属性那么强大,我们就可以用他来优化我们平时的操作。例如:拖拽,在mouseover阶段就用transform,在mousedown阶段在再用position绝对定位,这样是就可以减少repaint和reflow的操作、还有就是动画。。。等等。
————————————————

原文链接:https://blog.csdn.net/thewar196/article/details/124602244

posted @   rmticocean  阅读(859)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示