1、浏览器渲染机制

浏览器采用流式布局模型(Flow Based Layout)

浏览器会把HTML解析成DOM,把CSS解析成CSSOM,DOM和CSSOM合并就产生了渲染树(Render Tree)。

有了RenderTree,我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置,最后把节点绘制到页面上。

由于浏览器使用流式布局,对Render Tree的计算通常只需要遍历一次就可以完成,但table及其内部元素除外,他们可能需要多次计算,通常要花3倍于同等元素的时间,这也是为什么要避免使用table布局的原因之一。

为了构建渲染树,浏览器主要完成了以下工作:

从DOM树的根节点开始遍历每个可见节点。

对于每个可见的节点,找到CSSOM树中对应的规则,并应用它们。

根据每个可见节点以及其对应的样式,组合生成渲染树。

第一步中,既然说到了要遍历可见的节点,那么我们得先知道,什么节点是不可见的。不可见的节点包括:

一些不会渲染输出的节点,比如script、meta、link等。

一些通过css进行隐藏的节点。比如display:none。注意,利用visibility和opacity隐藏的节点,还是会显示在渲染树上的。只有display:none的节点才不会显示在渲染树上。

注意:渲染树只包含可见的节点.

2、回流 (refolw)

节点的几何属性或者布局发生改变被称为回流,一个元素的回流可能会导致了其所有子元素以及DOM中紧随其后的节点、祖先节点元素的随后的回流,所以一个节点的回流会引起页面某个部分甚至整个页面的回流。

3、重绘(repaint)

节点的样式改变且不影响布局的,比如color,visibility等,称为重绘。

** 重绘不一定回流,回流一定重绘。 **

4、 浏览器优化

现代浏览器大多都是通过队列机制来批量更新布局,浏览器会把修改操作放在队列中,至少一个浏览器刷新(即16.6ms)才会清空队列,但当你获取布局信息的时候,队列中可能有会影响这些属性或方法返回值的操作,即使没有,浏览器也会强制清空队列,触发回流与重绘来确保返回正确的值。

主要包括以下属性或方法:

offsetTop、offsetLeft、offsetWidth、offsetHeight

scrollTop、scrollLeft、scrollWidth、scrollHeight

clientTop、clientLeft、clientWidth、clientHeight

getComputedStyle()

getBoundingClientRect

相当一部分的浏览器的显示频率是16.7ms, 就是上图第一行的节奏,表现就是“我和你一步两步三步四步往前走……”。如果我们火力搞猛一点,例如搞个10ms setTimeout,就会是下面一行的模样——每第三个图形都无法绘制(红色箭头指示),表现就是“我和你一步两步 坑 四步往前走……”。

国庆北京高速,最多每16.7s通过一辆车,结果,突然插入一批setTimeout的军车,强行要10s通过。显然,这是超负荷的,要想顺利进行,只能让第三辆车直接消失(正如显示绘制第三帧的丢失)。然,这是不现实的,于是就有了会堵车!

同样的,显示器16.7ms刷新间隔之前发生了其他绘制请求(setTimeout),导致所有第三帧丢失,继而导致动画断续显示(堵车的感觉),这就是过度绘制带来的问题。不仅如此,这种计时器频率的降低也会对电池使用寿命造成负面影响,并会降低其他应用的性能。(这里是原文)

我比较认同下面这个观点

‘setTimeout为10ms,为什么我感觉应该丢失的是第二帧,第一帧10ms后进行绘制,此时浏览器刚开始进行渲染。然后过10ms,此时还没达到浏览器的显示频率是16.7ms,所以第二帧丢失,再过10ms,距离第一次绘制已经过去20ms了大于16.7ms,所以第三帧可以绘制。

上面这点歧义也只是计算上有点问题,但是问题原作者已经给我们解释得很清楚了。

过度绘制带来的问题一是会出现掉帧的情况(丢失某一时间点的动画)造成卡顿,二是大量的UI渲染任务聚集在后面会导致电池寿命及其他应用的性能。

而强制清空浏览器UI渲染队列会引起大量的UI渲染任务聚集在一次EventLoop中(同步中)去完成,自然会导致上面第二点,大量的UI渲染任务聚集在后面会导致电池寿命及其他应用的性能。

5、减少回流和重绘

5.1、批量修改DOM或者样式

最核心的思想就是对于对引起回流和重绘的操作不要一次一次的修改,应该用一个容器装起来,一次性修改

比如修改样式如下:

const el = document.getElementById('test');

el.style.padding = '5px';

el.style.borderLeft = '1px';

el.style.borderRight = '2px';

//可以优化为使用cssText或者class统一添加

const el = document.getElementById('test');

el.style.cssText += 'border-left: 1px; border-right: 2px; padding: 5px;';

//或者

const el = document.getElementById('test');

el.className += ' active';

再比如增加DOM节点:

考虑我们要执行一段批量插入节点的代码:

function appendDataToElement(appendToElement, data) {

let li;

for (let i = 0; i < data.length; i++) {

li = document.createElement('li');

li.textContent = 'text';

appendToElement.appendChild(li);

}

}

const ul = document.getElementById('list');

appendDataToElement(ul, data);

如上面这种写法会导致多次回流

优化方式可以用document.createDocumentFragment

const ul = document.getElementById('list');

const fragment = document.createDocumentFragment();

appendDataToElement(fragment, data);

ul.appendChild(fragment);

前面有说到渲染树回流、重绘都是针对可见元素,那么就有以下优化方案

原理就是利用display:none隐藏元素,进行各种增删改元素的操作,操作完再使其可见,对display:none隐藏元素进行操作是不会引起回流的。下面代码只会在ul显示的时候(display:block的时候)进行一次回流。

function appendDataToElement(appendToElement, data) {

let li;

for (let i = 0; i < data.length; i++) {

li = document.createElement('li');

li.textContent = 'text';

appendToElement.appendChild(li);

}

}

const ul = document.getElementById('list');

ul.style.display = 'none';

appendDataToElement(ul, data);

ul.style.display = 'block';

5.2、避免触发同步UI渲染

在前面浏览器优化那一章中,提到那些关于获取节点(元素)布局信息的属性不能过分使用,会引起浏览器的强制回流或重绘,也就是在同步中进行回流重绘,所以我们也需要减少对这类属性的使用。

例子如下

function initP() {

for (let i = 0; i < paragraphs.length; i++) {

paragraphs[i].style.width = box.offsetWidth + 'px';

}

}

这段代码看上去是没有什么问题,可是其实会造成很大的性能问题。在每次循环的时候,都读取了box的一个offsetWidth属性值,然后利用它来更新p标签的width属性。这就导致了每一次循环的时候,浏览器都必须先使上一次循环中的样式更新操作生效,才能响应本次循环的样式读取操作。每一次循环都会强制浏览器刷新队列。我们可以优化为:

const width = box.offsetWidth;

function initP() {

for (let i = 0; i < paragraphs.length; i++) {

paragraphs[i].style.width = width + 'px';

}

}

5.3、对于复杂动画效果,使用绝对定位让其脱离文档流

对于复杂动画效果,由于会经常的引起回流重绘,因此,我们可以使用绝对定位,让它脱离文档流。否则会引起父元素以及后续元素频繁的回流

可以看这个例子,可以打开调试面板查看FPS的变化

例子中在未优化前,元素未绝对定位,依靠margin的变化进行动画,引起大量的回流,而当使用了绝对定位,明显感觉FPS稳定在每秒60次,也就是16.6ms一次。

5.4、css3硬件加速(GPU加速)

比起考虑如何减少回流重绘,我们更期望的是,根本不要回流重绘。这个时候,css3硬件加速就闪亮登场啦!!

划重点:

使用css3硬件加速,可以让transform、opacity、filters这些动画不会引起回流重绘 。

对于动画的其它属性,比如background-color这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能

如何使用

常见的触发硬件加速的css属性:

transform

opacity

filters

Will-change

效果

我们可以先看个例子。我通过使用chrome的Performance捕获了动画一段时间里的回流重绘情况,实际结果如下图:

从图中我们可以看出,在动画进行的时候,没有发生任何的回流重绘。如果感兴趣你也可以自己做下实验。

重点

使用css3硬件加速,可以让transform、opacity、filters这些动画不会引起回流重绘

对于动画的其它属性,比如background-color这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能。

css3硬件加速的坑

当然,任何美好的东西都是会有对应的代价的,过犹不及。css3硬件加速还是有坑的:

如果你为太多元素使用css3硬件加速,会导致内存占用较大,会有性能问题。

在GPU渲染字体会导致抗锯齿无效。这是因为GPU和CPU的算法不同。因此如果你不在动画结束的时候关闭硬件加速,会产生字体模糊。

参考文章链接:

https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/24

https://www.zhangxinxu.com/wordpress/2013/09/css3-animation-requestanimationframe-tween-%e5%8a%a8%e7%94%bb%e7%ae%97%e6%b3%95/

标签:动画,浏览器,渲染,节点,回流,优化,重绘

来源: https://www.cnblogs.com/chenlei987/p/11447484.html

css3动画会造成回流重绘吗,重绘和回流以及如何优化相关推荐

  1. 浏览器:重绘(repaint)与回流/重排(reflow)

    一.从上面这个图上,我们可以看到,浏览器渲染过程如下: 1.解析HTML,生成DOM树,解析CSS,生成CSSOM树 2.将DOM树和CSSOM树结合,生成渲染树(Render Tree) 3.Lay ...

  2. 重绘(Repaint)和回流(Reflow)

    重绘和回流是渲染步骤中的⼀⼩节,但是这两个步骤对于性能影响很⼤. 重绘是当节点需要更改外观⽽不会影响布局的,⽐如改变 color 就叫称为重绘 回流是布局或者⼏何属性需要改变就称为回流. 回流必定会发 ...

  3. JavaScript 动画和CSS3动画有什么区别? (前端面试题!必会)

    1.CSS动画 优点: 1.1)浏览器可以对动画进行优化. 1.1.1 )浏览器使用requestAnimationFrame 比起setTimeout, setInterval 设置动画的优势主要是 ...

  4. JavaScript动画和CSS3动画的区别

    一.CSS动画 优点 浏览器可以对动画进行优化 浏览器使用域requestAnimationFrame类似的机制,requestAnimationFrame比起setTimeout,setInterv ...

  5. css3 动画 vs js 动画

    之前被问到过,css3 动画与 js 动画孰优孰劣,脑袋的第一反应就是性能上肯定 css3 动画会好很多,但别人说不对,我就在想,不对?难道还有别的原因吗?答案是肯定的.先来看看二者实现动画的原理吧. ...

  6. CSS3动画那么强,requestAnimationFrame还有毛线用--摘抄

    CSS3动画那么强,requestAnimationFrame还有毛线用? 这篇文章发布于 2013年09月30日,星期一,19:12,归类于 web综合. 阅读 197124 次, 今日 84 次 ...

  7. H5中CSS3动画的性能优化

    2020年的最后10天,愿你来年有始料不及的运气,也有突如其来的惊喜. 触发重布局的属性 有些节点,当你改变他时,会需要重新布局(这也意味着需要重新计算其他被影响的节点的位置和大小).这种情况下,被影 ...

  8. CSS3动画animation认识和Animate.css的使用

    CSS动画可以取代js动画 在移动端会更加流畅! 下面是一个的绘制太阳系各大行星运行轨迹笔记,可以自学参考! 首先我们需要创建一个@keyframes规则 @keyframes name{from{w ...

  9. html鼠标在ie上抖动,IE下CSS3动画抖动

    问题记录:IE11中执行淡入动画时出现抖动效果,效果如下: 抖动.gif 解决此问题需理解一些概念: 重排:重新生成布局 重绘:重新绘制 注意:重排必定导致重绘,重绘不一定需要重排:比如改变背景色,就 ...

最新文章

  1. python教程笔记(详细)
  2. Linux学习笔记之安装mplayer过程详解
  3. UOJ #514 [UR #19]通用测评号 (容斥原理、DP)
  4. 数据结构的简单理解(1)
  5. 机器学习实战:使用lightGBM预测饭店流量
  6. JMeter工具使用初探
  7. 足球点球 html5,身为西甲第一点球手,C罗只有5次让点经历,难怪点球破门过百...
  8. (29)VHDL实现时钟分频
  9. Xilinx PLL IP核功能仿真
  10. python内置对象是什么_Python的内置对象类型——元组、文件,python
  11. java hook 和反射_Java反射与hook混用反射某支付的方法
  12. 2018.12.17-dtoj-1170-最长公共子串
  13. ACM算法书籍推荐zz
  14. LeetCode 226 翻转二叉树
  15. Qt之Threads和QObjects
  16. oracle常用操作命令总结
  17. 用QLabel实现抽奖
  18. Java开发手册黄山版新增规约摘录
  19. 双浮点运算计算机在线,双浮点运算计算器
  20. 数据结构(五)树与二叉树-----堆

热门文章

  1. 喝汽水问题(使用c语言解决)
  2. 计算机控制综合应用题,2013计算机考研《操作系统》之综合应用题
  3. IBM经历的苦,谁能躲得掉?
  4. 图片剪切工具Jcrop在JavaScript中使用
  5. Windows server 2008 网络负载均衡配置
  6. 简单的sql server查询
  7. 仔细看private与public的区别
  8. idea 连接远程docker
  9. 前端设计师必知的background属性(有CSS3内容)
  10. 用FFmpeg玩转Android视频录制与压缩