8000 回流(Reflow)和重绘(Repaint) · Issue #60 · tcatche/tcatche.github.io · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

回流(Reflow)和重绘(Repaint) #60

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
tcatche opened this issue Sep 18, 2017 · 0 comments
Open

回流(Reflow)和重绘(Repaint) #60

8000 tcatche opened this issue Sep 18, 2017 · 0 comments

Comments

@tcatche
Copy link
Owner
tcatche commented Sep 18, 2017

本文博客地址:回流(Reflow)和重绘(Repaint).

最近在重看一些基础的理论知识,看到了回流(Reflow)和重绘(Repaint)的概念,惭愧的发现,对此竟然说不出太详细的内容,在此参阅一些文章进行一个总结。

在了解这两个概念之前先了解一下 HTML 的渲染过程。

HTML 渲染过程

浏览的引擎处理 HTML 的基本流程分为如下四个步骤:

1.解析 HTML 并构建 DOM 树和 CSSOM 树。浏览器对 HTML 进行解析,将 HTML 标记转换成文档对象模型 (DOM),CSS 标记则被转换成 CSS 对象模型 (CSSOM),而 DOM 和 CSSOM 是独立的数据结构。在解析过程中,DOM 树包含了所有的 html 标签,包括不展示的 head 节点和 display:none 的节点,而 CSSOM 树则会去掉浏览器不能识别的样式,比如不支持的浏览器前缀(chrome不支持的-moz-前缀)和 hack(如firefox不支持_开头的样式)。

2.构建 render 树。将 DOM 树和 CSSOM 树合并为 render 树,在这个过程中,需要计算每一个呈现对象的可视化属性,会去掉不展示在页面上的节点(如 display:none 和 head 节点等)。

3.布局 render 树。render 树在创建完成时,并不包含位置和大小信息。计算这些值的过程称为布局或重排。从 render 树的根节点((对应于 HTML 文档的 元素))递归调用,计算每一个元素的位置和大小信息。

4.使用 render 树绘制页面。在绘制阶段,系统会遍历 render 树,将其内容显示在屏幕上。绘制的顺序其实就是元素进入堆栈样式上下文的顺序。这些堆栈会从后往前绘制,因此这样的顺序会影响绘制。
这就是浏览器引擎处理页面的基本流程了。接下来我们看一下回流和重绘的概念

回流(Reflow)和重绘(Repaint)

回流和重绘分别出现在上面的第三和第四步。

  • 回流(Reflow):当 render 树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘。
  • 重绘(Repaint):当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响 render 树重新布局的,比如修改了元素的 background-color。

由上定义可以看出,回流必将引起重绘,而重绘不一定会引起回流。明显回流的成本比重绘的成本高得多。

引起回流和重绘的操作

任何对 render 树中元素的操作都会引起回流或者重绘:

  • 改变 DOM 树结构,比如添加或者删除可见的元素、改变文本内容、改变位置;
  • 改变元素几何尺寸:边距、填充、边框、宽度和高度;
  • 用户改变浏览器窗口尺寸;
  • CSS伪类激活,在用户交互过程中发生;
  • 获取某些属性,浏览器一般对引起回流、重绘的操作进行优化,将多个操作合并在固定时候执行,如果此时获取一些 style 信息,则会提前执行操作,以提供准确数值。常见的这类信息如:offsetTop/offsetLeft/offsetWidth/offsetHeightscrollTop/Left/Width/Height,具体可以查看 CSS Triggers

减少回流和重绘

减少回流、重绘其实就是需要减少对render 树的操作,合并多次 DOM 和样式的修改,并减少对一些style信息的请求。具体有:

避免多次更改样式属性,合并为一个

当更该样式的时候,可以更改class 或者将多个更改操作合并为一个:

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

// 比较好的写法
el.className += " className1";
 
// 比较好的写法
el.style.cssText += "; 
left: " + left + "px; 
top: " + top + "px;";

将要操作的元素“离线处理”

主要注意三点:

  • 使用 DocumentFragment 进行缓存操作,引发一次回流和重绘;
  • 使用 display:none 技术,只引发两次回流和重绘;
  • 使用 cloneNode(true or false) 和 replaceChild 技术,引发一次回流和重绘;

减少操作影响的元素

将导致多次回流的元素,position 属性设为 absolute 或 fixed,这样此元素就脱离了文档流,它的变化不会影响到其他元素。例如有动画效果的元素就最好设置为绝对定位。

读取引起回流的属性,尽量缓存

// 不好的写法
for(;;) {
    el.style.left = el.offsetLeft + 5 + "px";
    el.style.top  = el.offsetTop  + 5 + "px";
}

// 这样写好点
var left = el.offsetLeft,
top  = el.offsetTop,
s = el.style;
for(;;) {
    left += 10;
    top  += 10;
    s.left = left + "px";
    s.top  = top  + "px";
}

参考

扩展阅读

@tcatche tcatche changed the title React 内部原理,第一部分:基础渲染 回流(Reflow)和重绘(Repaint) Sep 18, 2017
@tcatche tcatche closed this as completed Sep 19, 2017
@tcatche tcatche reopened this Sep 19, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant
0