关于浏览器:浏览器的重排和重绘

35次阅读

共计 3390 个字符,预计需要花费 9 分钟才能阅读完成。

参考文章:https://www.html5rocks.com/zh/tutorials/internals/howbrowserswork/

浏览器的高层构造


1、用户界面 – 包含地址栏、后退 / 后退按钮、书签菜单等。
2、浏览器引擎 – 在用户界面和出现引擎之间传送指令。
3、渲染引擎 – 负责显示申请的内容。
4、网络 – 用于网络调用,比方 http 申请。
5、用户界面后端 – 用于绘制根本的窗口小部件。
6、javascript 解释器 – 用于解析和执行 javascript 代码。
7、数据存储 – 数据长久化。

和大多数浏览器不同,Chrome 浏览器的每个标签页都别离对应一个渲染引擎实例。每个标签页都是一个独立的过程。

渲染引擎主流程


1、解析 HTML 文档,构建 DOM 树。解析内部 CSS 文件和行内款式,生成 CSS 规定树。
2、将 DOM 树和 CSS 规定树连贯在一起创立了另一个渲染树 Render Tree,它是一个带有多个视觉属性的(色彩、尺寸)的矩形,这些矩形的排列程序就是它们在屏幕上的显示程序。
3、开始进入“布局”解决阶段,也就是为每个节点调配一个呈现在屏幕上的确切坐标。
4、“绘制”阶段,渲染引擎遍历渲染树,由用户后端层将每个节点绘制进去。

主流程示例

出现树构建

在 DOM 树构建的同时,浏览器还会构建另一个树结构:出现树。这是由可视化元素依照其显示程序而组成的树,也是文档的可视化示意。它的作用是让您依照正确的程序绘制内容。

Firefox 将出现树中的元素称为“框架”。WebKit 应用的术语是出现器或出现对象。

出现器晓得如何布局并将本身及其子元素绘制进去。

每一个出现器都代表了一个矩形的区域,通常对应于相干节点的 CSS 框,它蕴含诸如宽度、高度和地位等几何信息。

重排 or 布局

渲染引擎在渲染树创立实现的时候,并不蕴含地位和大小信息。计算这些值的过程称为布局或重排。

HTML 采纳基于流的布局模型,这意味着大多数状况下只有一次遍历就能计算出几何信息。处于流中靠后地位元素不会影响靠前地位元素的几何特色,因而布局能够依照从左往右,从上往下的程序遍历文档。

坐标系是绝对于根框架而建设的,应用的是上坐标和左坐标。

布局是一个递归的过程。它从根出现器 <html> 开始,而后递归遍历局部或所有的框架层次结构,为每一个须要计算的出现器计算几何信息。

根出现器的地位右边是 0,0,其尺寸为视口(也就是浏览器窗口的可见区域)。

所有的出现器都会有一个“layout”或“reflow”办法,没一个出现器都会调用须要布局的子代的 layout 办法。
**

Dirty 位零碎

为防止对所有细小更改都进行整体布局,浏览器采纳了一种“dirty 位”零碎。如果某个出现器产生了更改,或者将本身及其子代标注为“dirty”,则须要进行布局。

有两种标记:“dirty”和“children are dirty”。“children are dirty”示意只管出现器本身没有变动,但它至多有一个子代须要布局。

全量布局和增量布局

全局布局是指触发了整个出现树范畴的布局,触发起因可能包含:

  1. 影响所有出现器的全局款式更改,例如字体大小更改。
  2. 屏幕大小调整。

布局能够采纳增量形式,也就是只对 dirty 出现器进行布局。

全局布局往往是同步触发的。
增量布局是异步执行的,webkit 有用于执行增量布局的计时器:对出现树进行遍历,并对 dirty 出现器进行布局。

绘制

在绘制阶段,零碎会便当出现树,并调用出现树的“paint”办法,将出现树的内容显示在屏幕上。

绘制也分为全局绘制和增量绘制。

增量绘制中,局部出现器产生了更改,然而不会影响整个树,更改后的出现器将其在屏幕上对应的矩形区域设为有效,这导致操作系统将其视为一块“dirty 区域”,并生成“paint”事件。操作系统会奇妙地将多个区域合并成一个。

绘制程序

绘制的程序就是元素进入堆栈款式上下文的程序。上面是 css2 标准的绘制流程程序:

https://drafts.csswg.org/css2/#stacking-context

Within each stacking context, the following layers are painted in back-to-front order:

  1. the background and borders of the element forming the stacking context.
  2. the child stacking contexts with negative stack levels (most negative first).
  3. the in-flow, non-inline-level, non-positioned descendants.
  4. the non-positioned floats.
  5. the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
  6. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
  7. the child stacking contexts with positive stack levels (least positive first).

重排和重绘区别

重排顾名思义就是重新排列,意味着从新计算文档中元素的地位和几何信息(元素的地位、大小),会影响局部或整个页面的布局。元素的重排将导致 DOM 中所有子元素和其余兄弟元素重新排列。

重绘是更改元素的可见性,然而不影响元素的布局。例如可见性、背景色、轮廓等。

不论是重排还是重绘都是很“低廉“的操作。

什么会触发重排和重绘?

  • 增加、删除、更新 DOM 节点都会触发重排
  • 应用 display: none 暗藏元素会触发重排和重绘
  • 应用 visibility:hidden 只会引起重绘,因为没有布局和地位的变更
  • 挪动节点、增加动画都会触发重排和重绘
  • 扭转浏览器窗口大小会触发重排
  • 更改元素字体大小会触发重排
  • 增加或者删除款式会触发重排和重绘
  • 操作 DOM 脚本是低廉的操作,因为每次 document 或者 document 的局部扭转时,它们都会从新计算。
var bodyStyle = document.body.style; // cache

bodyStyle.padding = "20px"; // reflow, repaint
bodyStyle.border = "10px solid red"; // reflow, repaint

bodyStyle.color = "blue"; // repaint only, no dimensions changed
bstyle.backgroundColor = "#cc0000"; // repaint

bodyStyle.fontSize = "2em"; // reflow, repaint

// new DOM element - reflow, repaint
document.body.appendChild(document.createTextNode('Hello!'));

如何缩小重排和重绘?

  • 不要一个一个更改款式,从健壮性和可维护性来说咱们应该扭转 class 名称,而不是间接批改 style。如果 style 是动静的,那么能够编辑 cssText 属性。
// bad
var left = 10;
var top = 10;
el.style.left = left + "px";
el.style.top  = top  + "px";

// better 
el.className += "theclassname";

// or when top and left are calculated dynamically...

// better
el.style.cssText += "; left:" + left + "px; top:" + top + "px;";
  • 批量更改 DOM。应用 documentFragment 保留零时的扭转,复制、更新、替换节点,应用 display:none(1 次重排,1 次重绘),而后更改 100 次,再从新显示(总共 2 次重排,2 次重绘)。
  • 不要反复的申请计算属性(getComputedStyle),将它缓存起来。屡次读写都会触发重排。咱们要做的是先读取所有内容,而后再写。**

============ 哎呀,奇奇怪怪的小常识又减少了,2021-02-24 =================

正文完
 0