摘要:例如对于复杂动画效果,由于会经常的引起回流重绘,因此,我们可以使用绝对定位,让它脱离文档流,成为一个多带带的图层。
浏览器的渲染过程
从上面这个图上,我们可以看到,浏览器渲染过程如下
解析HTML生成DOM树,解析CSS生成CSSOM树
将DOM树和CSSOM树结合生成渲染树renderTree
Layout(回流): 根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小)
Painting(重绘): 根据渲染树以及回流得到的几何信息,得到节点的绝对像素
Display:将像素发送给GPU,展示在页面上。
生成渲染树(RenderTree)为了构建渲染树,浏览器主要完成了以下工作
从DOM树的根节点开始遍历每个可见节点。
对于每个可见的节点,找到CSSOM树中对应的规则,并应用它们。
根据每个可见节点以及其对应的样式,组合生成渲染树。
第一步中,既然说到了要遍历可见的节点,那么我们得先知道,什么节点是不可见的。不可见的节点包括:
一些不会渲染输出的节点,比如script、meta、link等。
一些通过css进行隐藏的节点。比如display:none。注意,利用visibility和opacity隐藏的节点,还是会显示在渲染树上的。只有display:none的节点才不会显示在渲染树上。
回流(Layout)前面我们通过构造渲染树,我们将可见DOM节点以及它对应的样式结合起来,可是我们还需要计算它们在设备视口(viewport)内的确切位置和大小,这个计算的阶段就是回流。
为了弄清每个对象在网站上的确切大小和位置,浏览器从渲染树的根节点开始遍历,而在回流这个阶段,我们就需要根据视口具体的宽度,将其转为实际的像素值
通过回流(Layout)阶段,我们知道了所有的可见节点的样式和具体的几何信息(位置、大小),那么我们就可以将渲染树的每个节点都转换为屏幕上的实际像素,这个阶段就叫做重绘节点。
何时发生回流重绘回流阶段是计算节点的几何信息和位置,那么当页面布局或者几何信息发生改变时,就需要回流。
添加或者删除可见的DOM元素
元素的位置、尺寸发生变化
页面开始渲染的时候(这肯定避免不了)
浏览器的视口尺寸大小发生改变(因为回流是根据浏览器视口的大小来计算元素的位置和尺寸大小)
注意:回流一定会触发重绘,而重绘(非几何信息的样式发生改变)不一定会回流, reflow回流的成本开销要高于repaint重绘,一个节点的回流往往回导致子节点以及同级节点的回流;
根据改变的范围和程度,渲染树中或大或小的部分需要重新计算,有些改变会触发整个页面的重排,比如,滚动条出现的时候或者修改了根节点。
基于回流(Layout)、重绘(Painting)的优化方法 避免扰乱现代浏览器的优化机制在现代浏览器的中,由于每次回流、重绘的时候,都需要额外的计算消耗,因此会通过队列化修改,并批量执行来优化这一过程。浏览器会将修改操作放入队列里面,直到过了一段时间或者达到一个阈值,才清空队列。
但是当你获取布局信息时,会强制刷新队列,例如:
offsetTop、offsetLeft、offsetWidth、offsetHeight scrollTop、scrollLeft、scrollWidth、scrollHeight clientTop、clientLeft、clientWidth、clientHeight getComputedStyle() getBoundingClientRect()
上面这些方法,都需要获取最新的布局信息,所以浏览器会强制刷新队列并执行回流、重绘,来获取最新的信息。
因此我们在修改样式的时候,应该尽量避免使用上面的属性、方法,如果非要使用,可以先缓存起来然后一起获取。
考虑以下代码
const el = document.getElementById("el") el.style.padding = "xxx" el.style.margin = "xxx" el.style.border = "xxx"
这里元素的几何信息有三次被修改了,但是现代浏览器会将起缓存起来,但是如果这期间有通过前面列出来的属性、方法访问位置信息的话就会触发三次回流、重绘。所以还是建议通过cssText或者class的方法一次性修改。
el.style.cssText += "border-left: 1px; border-right: 2px; padding: 5px;"; // 或者 el.className += "xxx";批量修改DOM
当我们需要对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"); ul.style.display = "none"; // 首先脱离文档流 appendDataToElement(ul, data); ul.style.display = "block"; // 操作完以后再可见
使用文档片段(document fragment)在当前DOM之外构建一个子树,再把它拷贝回文档。
const ul = document.getElementById("list"); const fragment = document.createDocumentFragment() appendDataToElement(fragment , data); ul.appendChild(fragment )独立图层
一个图层的回流和重绘只会在该图层当中进行,不会影响其他图层,所以有必要的时候,可以将某些元素放到多带带的图层。
例如对于复杂动画效果,由于会经常的引起回流重绘,因此,我们可以使用绝对定位,让它脱离文档流, 成为一个多带带的图层。否则会引起父元素以及后续元素频繁的回流。但是因该尽量少量使用图层,因为图层的合成是特别消耗性能,一个页面当中不能有过多的图层, 在使用了图层之后需要进行前后对比
会自动建立图层的情况:
3d或者透视变换、过渡css属性
使用
flash
多透明度做 css动画
其他优化用translate替代top改变: top会触发回流,而前者不会
用opacity替代visibility: 前者回流重绘都不会触发(前提是它多带带在一个图层),后者两个都会触发
不要使用table布局,table的可能很小的一个改动会造成回流,很影响性能,应该尽量使用 div。
动画实现的速度选择:
对于动画新建图层
启用GPU硬件加速: 使用transform:translateZ(0) 、transform:translate3d(0,0,0)来开启GPU硬件加速
CSS 与 JS 是这样阻塞 DOM 解析和渲染的通过与引入外部资源,当解析到该标签的时候,会进行下载。
CSS脚本的加载不会阻塞 DOM 解析过程,但是会阻塞渲染过程(painting)
JS脚本的加载与执行会阻塞 DOM 解析过程, 但是不会阻塞后续资源的加载
JS脚本的加载中,如果你确定没必要阻塞 DOM 解析的话,不妨按需要加上 defer 或者 async 属性,此时脚本下载的过程中是不会阻塞 DOM 解析的。
浏览器遇到 且没有 defer 或 async 属性的标签时,为了为标签内部的js提供最新的信息,会触发页面的回流、重绘过程。
如果前面 CSS 资源尚未加载完毕时,浏览器会等待它加载完毕之后再执行脚本。即 css 不阻塞 js 的加载,但阻塞它的执行。
所以最好放底部(防止阻塞DOM解析)。最好放头部(为渲染过程提供样式)。如果头部同时有与的情况下,最好将放在上面(为了防止CSS脚本加载时间过长,使js等待时间也很长)dd
defer和async直接看图吧,绿色的代表 html 解析,蓝色的代表 javascript 脚本的下载,红色的代表 javaScript 脚本的执行。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/53475.html
摘要:所以由此来看重绘不一定导致回流,回流一定会导致重绘前面我们说回流和重绘是会对进行修改,会消耗性能,所以我们要尽可能减少回流和重绘的次数。浏览器自己也清楚,如果每次操作都即时地反馈一次回流或重绘,那么性能上来说是扛不住的。 回流(Reflow)重绘(Repaint) 什么时候会触发回流或重绘呢? 当我们对dom 进行修改当时候会引发它外观(样式)上的改变时,就会触发回流或重绘。这个过程本...
摘要:何时发生有大量的用户行为以及潜在的改变会触发回流。这样就会让多次的回流重绘变成一次回流重绘。因为上的操作不会引发回流和重绘。参考文章回流与重绘性能让变慢参考文章浏览器的重绘与重排 推荐了解的知识:基本的HTML,基本的JavaScript,以及一些css工作原理方面的知识 浏览器的渲染原理 css的加载和解析不会阻塞html文档的解析 css的解析会阻塞js的执行,必须等到CSSOM...
摘要:对于复杂动画效果使用绝对定位让其脱离文档流对于复杂动画效果,由于会经常的引起回流重绘,因此,我们可以使用绝对定位,让它脱离文档流。硬件加速加速比起考虑如何减少回流重绘,我们更期望的是,根本不要回流重绘。 回流和重绘可以说是每一个web开发者都经常听到的两个词语,我也不例外,可是我之前一直不是很清楚这两步具体做了什么事情。最近由于部门内部要做分享,所以对其进行了一些研究,看了一些博客和书...
摘要:否则会引起父元素以及后续元素频繁的回流。硬件加速加速硬件加速加速比起考虑如何减少回流重绘,我们更期望的是,根本不要回流重绘。这个时候,硬件加速就闪亮登场啦划重点使用硬件加速,可以让这些动画不会引起回流重绘。回流和重绘可以说是每一个web开发者都经常听到的两个词语,我也不例外,可是一直不是很清楚这两步具体做了什么事情。最近由于部门内部要做分享,所以对其进行了一些研究,看了一些博客和书籍,整理了...
摘要:硬件加速加速比起考虑如何减少回流重绘,我们更期望的是,根本不要回流重绘。这个时候,硬件加速就闪亮登场啦划重点使用硬件加速,可以让这些动画不会引起回流重绘。 本文由云+社区发表 回流和重绘可以说是每一个web开发者都经常听到的两个词语,可是可能有很多人不是很清楚这两步具体做了什么事情。最近有空对其进行了一些研究,看了一些博客和书籍,整理了一些内容并且结合一些例子,写了这篇文章,希望可以帮...
阅读 2751·2021-11-02 14:42
阅读 3146·2021-10-08 10:04
阅读 1169·2019-08-30 15:55
阅读 1003·2019-08-30 15:54
阅读 2293·2019-08-30 15:43
阅读 1662·2019-08-29 15:18
阅读 845·2019-08-29 11:11
阅读 2331·2019-08-26 13:52