杂记(浏览器渲染)

Firefox、Chrome和Safari是基于两种渲染引擎构建的,Firefox使用Geoko(Mozilla自主研发的渲染引擎),Safari和Chrome都使用webkit。

1 渲染主流程

渲染流程

  • 1、 浏览器将HTML文档解析成 DOM 树
  • 2、 将CSS解析成 Rule 树
  • 3、 DOM 树与 Rule 树一起构造层 Render 树(渲染树并不等同于 DOM 树,因为一些像<head>标签或display:none的对象并没有放置在渲染树中)
  • 4、layout(布局)Render tree,有了Render 树,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义,布局顾名思义就是计算出每个节点在屏幕中的位置
  • 5、paint(绘制)页面

注意:上述这个过程是逐步完成的,为了更好的用户体验,渲染引擎并不会等到所有的html都解析完成之后再去构建和布局render树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容

1.2 reflow(回流)

当浏览器发现某个部分发生变化影响了布局,需要重新渲染,这个过程叫 reflow。reflow 几乎是无法避免的。比如树状目录的折叠、展开(使用display:none),事件函数引起页面上某些元素的占位面积、定位方式、边距等属性的变化,还有浏览器窗口尺寸改变导致resize事件发生时等,都将引起浏览器的回流,都会引起它内部、周围甚至整个页面的重新渲染,通常我们都无法预估浏览器到底会 reflow 哪一部分的代码。

1.3 repaint(重绘)

改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,屏幕的一部分要重绘,这过程就叫repaint(重绘)

1、display:none的节点不会被加入Render Tree,而visibility: hidden 则会,所以,如果某个节点最开始是不显示的,设为display:none是更优的
2、display:none会触发 reflow,而visibility:hidden只会触发 repaint,因为没有发现位置变化
3、回流必将引起重绘,而重绘不一定会引起回流
4、回流比重绘的代价要更高

2 减少回流与重绘

很多浏览器都会优化,浏览器会维护1个队列,把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。
但有时候我们写的一些代码可能会强制浏览器提前flush队列,比如:

  • 访问offsetTopoffsetLeftoffsetWidthoffsetHeight属性
  • 访问scrollTop/Left/Width/Height属性
  • 访问clientTop/Left/Width/Height属性
  • 访问widthheight属性
  • 请求了getComputedStyle(), 或者 IE的currentStyle

当你请求上面的一些属性的时候,浏览器为了给你最精确的值,需要flush队列,因为队列中可能会有影响到这些值的操作。

减少回流、重绘其实就是需要减少对render tree的操作(合并多次多DOM和样式的修改),并减少对一些style信息的请求,如:
1、直接改变className,如果动态改变样式,则使用cssText(合并多次样式修改)

/* 不好的写法 */
var left = 1;
var top = 1;
el.style.left = left + "px";
el.style.top = top + "px";

/* 比较好的写法,使用cssText */
el.style.cssText += "; 
left: " + left + "px; 
top: " + top + "px;";

/* 比较好的写法,改变类名 */
el.className += " className1";

2、不要经常访问会引起浏览器flush队列的属性,如果你确实要访问,利用缓存

posted @ 2017-09-17 21:58  Seiei  阅读(112)  评论(0编辑  收藏  举报