本文首发于个人我的网站: litgod.net
以前面试的大佬问我关于重排重绘的原理和具体操做,一会儿把我问蒙了。回家便默默地把问题记下来,仔细总结……在阅读了一些文章后,本身也有了必定的理解,因此分享给你们。但愿你们也能耐心把这篇文章看完,认真思考,完全掌握这个知识点!css
1.HTML 被 HTML 解析器解析成 DOM 树;
2.CSS 被 CSS 解析器解析成 CSSOM 树;
3.结合 DOM 树和 CSSOM 树,生成一棵渲染树(Render Tree),这一过程称为 Attachment;
4.生成布局(flow),浏览器在屏幕上“画”出渲染树中的全部节点;
5.将布局绘制(paint)在屏幕上,显示出整个页面。html
第四步和第五步是最耗时的部分,这两步合起来,就是咱们一般所说的渲染。前端
在页面的生命周期中,网页生成的时候,至少会渲染一次。在用户访问的过程当中,还会不断触发重排(reflow)和重绘(repaint),无论页面发生了重绘仍是重排,都会影响性能,最可怕的是重排,会使咱们付出高额的性能代价,因此咱们应尽可能避免。面试
大,在这个语境里的意思是:谁能影响谁?segmentfault
就如上面的概念同样,单单改变元素的外观,确定不会引发网页从新生成布局,但当浏览器完成重排以后,将会从新绘制受到这次重排影响的部分。好比改变元素高度,这个元素乃至周边dom都须要从新绘制。浏览器
也就是说:重绘不必定致使重排,但重排必定会致使重绘。缓存
当DOM的变化影响了元素的几何信息(元素的的位置和尺寸大小),浏览器须要从新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫作重排。网络
重排也叫回流,简单的说就是从新生成布局,从新排列元素。dom
:hover
)getComputedStyle
方法,或者IE里的 currentStyle
时,也会触发重排,原理是同样的,都为求一个“即时性”和“准确性”。常见引发重排属性和方法 | -- | -- | -- |
---|---|---|---|
width | height | margin | padding |
display | border-width | border | position |
overflow | font-size | vertical-align | min-height |
clientWidth | clientHeight | clientTop | clientLeft |
offsetWudth | offsetHeight | offsetTop | offsetLeft |
scrollWidth | scrollHeight | scrollTop | scrollLeft |
scrollIntoView() | scrollTo() | getComputedStyle() | |
getBoundingClientRect() | scrollIntoViewIfNeeded() |
因为浏览器渲染界面是基于流失布局模型的,因此触发重排时会对周围DOM从新排列,影响的范围有两种:ide
全局范围重排:
<body> <div class="hello"> <h4>hello</h4> <p><strong>Name:</strong>BDing</p> <h5>male</h5> <ol> <li>coding</li> <li>loving</li> </ol> </div> </body>
当p节点上发生reflow时,hello和body也会从新渲染,甚至h5和ol都会收到影响。
局部范围重排:
用局部布局来解释这种现象:把一个dom的宽高之类的几何信息定死,而后在dom内部触发重排,就只会从新渲染该dom内部的元素,而不会影响到外界。
当一个元素的外观发生改变,但没有改变布局,从新把元素外观绘制出来的过程,叫作重绘。
属性: | -- | -- | -- |
---|---|---|---|
color | border-style | visibility | background |
text-decoration | background-image | background-position | background-repeat |
outline-color | outline | outline-style | border-radius |
outline-width | box-shadow | background-size |
重排的代价是高昂的,会破坏用户体验,而且让UI展现很是迟缓。经过减小重排的负面影响来提升用户体验的最简单方式就是尽量的减小重排次数,重排范围。下面是一些行之有效的建议,你们能够用来参考。
咱们应该尽可能以局部布局的形式组织html结构,尽量小的影响重排的范围。
不要频繁的操做样式,对于一个静态页面来讲,明智且可维护的作法是更改类名而不是修改样式,对于动态改变的样式来讲,相较每次微小修改都直接触及元素,更好的办法是统一在 cssText
变量中编辑。虽然如今大部分现代浏览器都会有 Flush
队列进行渲染队列优化,可是有些老版本的浏览器好比IE6的效率依然低下。
// bad var left = 10; var top = 10; el.style.left = left + "px"; el.style.top = top + "px"; // 当top和left的值是动态计算而成时... // better el.style.cssText += "; left: " + left + "px; top: " + top + "px;"; // better el.className += " className";
DOM 的多个读操做(或多个写操做),应该放在一块儿。不要两个读操做之间,加入一个写操做。
// bad 强制刷新 触发四次重排+重绘 div.style.left = div.offsetLeft + 1 + 'px'; div.style.top = div.offsetTop + 1 + 'px'; div.style.right = div.offsetRight + 1 + 'px'; div.style.bottom = div.offsetBottom + 1 + 'px'; // good 缓存布局信息 至关于读写分离 触发一次重排+重绘 var curLeft = div.offsetLeft; var curTop = div.offsetTop; var curRight = div.offsetRight; var curBottom = div.offsetBottom; div.style.left = curLeft + 1 + 'px'; div.style.top = curTop + 1 + 'px'; div.style.right = curRight + 1 + 'px'; div.style.bottom = curBottom + 1 + 'px';
原来的操做会致使四次重排,读写分离以后实际上只触发了一次重排,这都得益于浏览器的渲染队列机制:
当咱们修改了元素的几何属性,致使浏览器触发重排或重绘时。它会把该操做放进渲染队列,等到队列中的操做到了必定的数量或者到了必定的时间间隔时,浏览器就会批量执行这些操做。
“离线”意味着不在当前的 DOM 树中作修改,咱们能够这样作:
一旦咱们给元素设置 display:none
时(只有一次重排重绘),元素便不会再存在在渲染树中,至关于将其从页面上“拿掉”,咱们以后的操做将不会触发重排和重绘,添加足够多的变动后,经过 display
属性显示(另外一次重排重绘)。经过这种方式即便大量变动也只触发两次重排。另外,visibility : hidden
的元素只对重绘有影响,不影响重排。
dom
碎片,在它上面批量操做 dom
,操做完成以后,再添加到文档中,这样只会触发一次重排。使用绝对定位会使的该元素单独成为渲染树中 body
的一个子元素,重排开销比较小,不会对其它节点形成太多影响。当你在这些节点上放置这个元素时,一些其它在这个区域内的节点可能须要重绘,可是不须要重排。
position
属性为 absolute
或 fixed
的元素上,这样对其余元素影响较小。动画效果还应牺牲一些平滑,来换取速度,这中间的度本身衡量:
好比实现一个动画,以1个像素为单位移动这样最平滑,可是Layout就会过于频繁,大量消耗CPU资源,若是以3个像素为单位移动则会好不少
GPU
硬件加速是指应用 GPU
的图形性能对浏览器中的一些图形操做交给 GPU
来完成,由于 GPU
是专门为处理图形而设计,因此它在速度和能耗上更有效率。GPU
加速一般包括如下几个部分:Canvas2D,布局合成, CSS3转换(transitions),CSS3 3D变换(transforms),WebGL和视频(video)。
1.打开开发者工具:点击 Performance 左侧有个小圆点 点击刷新页面会录制整个页面加载出来 时间的分配状况。以下图
哪一种色块比较多,就说明性能耗费在那里。色块越长,问题越大。
2.点击 Event Log:单独勾选 Loading 项会显示 html 和 css 加载时间。以下图:
3.解析完 DOM+CSSOM 以后会生成一个渲染树 Render Tree,就是 DOM 和 CSSOM 的一一对应关系。
4.经过渲染树中在屏幕上“画”出的全部节点,称为渲染。
很是感谢你看完了这篇很长的文章,也但愿你们能重视重排的这些问题,在咱们平时的开发中,也须要有意识的规避这些问题,才能让咱们写出来的代码更规范!
掌握浏览器重绘(repaint)重排(reflow))-前端进阶
csstriggers
CSS硬件加速的好与坏