reflow(回流、重排)

    repaint(重绘)

    浏览器的渲染机制

    1. 浏览器采用流式布局模型
    2. 首先浏览器会将html解析成dom 树,css 解析成 cssom,把二者结合起来,产生一个 render tree

    浏览器的渲染原理
    浏览器是多线程的,至少有三个常驻线程:JavaScript引擎线程、GUI渲染线程、浏览器事件触发线程

    js是单线程的,js在浏览器中可以是多线程的。

    JavaScript引擎线程:
    单线程的,解析执行js代码的

    GUI渲染线程:
    渲染页面的,和js 引擎是互斥的,挂起
    这就是js阻塞页面加载

    浏览器事件触发线程:
    当一个事件被触发的时候,这个线程会把事件添加到任务队列的队尾,等待 js引擎的处理

    浏览器
    是一个应用软件
    内核:
    trident:ie
    webkit 内核:chrome、safari
    gecko:firefox

    浏览器渲染的主要步骤:

    1. 将获取的 HTML 文档解析成 dom 树

      在解析开始的时候,浏览器会启用另外一个线程来下载css文件、静态资源等文件,如果 遇到script 标签就停止解析,转而去执行 js 和 加载 js文件,完成之后,再去继续解析 css 等资源

    2. css 下载完成之后,对css 进行解析,得到 cssom 树

    3. 当 dom 树和 cssom 树都构建完成之后,会根据他们生成一颗 render tree,渲染树
    4. 布局 layout

      浏览器采用流式处理的办法对render tree 上的所有节点进行遍历,计算它们在屏幕上的布置

    5. 绘制,遍历 render tree ,将其绘制在屏幕上

    渲染的具体过程:
    将获取的 HTML 文档解析成 dom 树

    display:none 元素也会在 dom 树中 注释也会在 dom 树中 script 标签也会在 dom 树中

    cssom 树

    css 解析可以与dom解析同时进行 css 的解析 与 script 执行互斥 在webkit内核中进行了优化,只有在js访问css的时候才会发生互斥

    render tree

    这棵树是将来要显示到页面上的内容 遍历 dom 树节点,为每一个节点加上合适的css样式 display:none 的元素不会显示在渲染树中 visibility:hidden 会显示在渲染树中 每个节点的宽度和高度、背景颜色等信息会被确定

    布局layout

    遍历渲染树,计算上面每一个节点的位置信息,将其渲染到页面上的正确位置 float、absolute、fixed 脱离文档流,指的就是脱离 渲染树 重排发生在这一阶段

    绘制

    在绘制阶段,浏览器会遍历渲染树,调用渲染器的paint() 方法在屏幕上显示内容 GUI线程完成这一工作

    阻塞渲染

    当浏览器对HTML页面进行解析的时候,如果遇到了 script 标签 内部脚本就等到脚本执行结束再去继续解析,如果是外部脚本,要等到下载完成 在解析页面。

    如果脚本还操作了 css,此时 cssom 还没有构建完成,会停止js 的加载,直到 cssom 树构建完成 因为CSSOM树中包含了各个节点的样式信息,CSSOM树没有加载完成就没有办法进入下一阶段,在这之前用户看到的页面一直是空白的。这也是为什么要把CSS代码放在标签中的原因。

    为什么遇到script标签就是要停下来HTML文档的解析,因为js脚本中可能包含有对DOM或者CSSOM的操作,脚本解析会将脚本中改变DOM和CSS的地方分别解析出来,追加到DOM树和CSSOM规则树上。

    回流

    回流通俗的来讲就是页面的布局发生了变化,浏览器需要重新的计算各个节点的位置,大小等信息了,浏览器会从root frame递归向下计算。这个回去重新计算的过程就是回流。回流是无法避免的,并且也不知道页面具体哪部分会受到影响,因为他们是相互依存,互相影响的关系。

    哪些操作会引起回流?

    网页初始化的时候 DOM操作(元素添加、删除、修改、元素顺序变化) 内容变化 添加删除样式表 窗口缩放 伪类激活,例如 hover 悬停 JS 获取 Layout 属性值(如:offsetLeft、scrollTop、getComputedStyle 等)也会引起回流。因为浏览器需要通过回流计算最新值

    回流必定引起重绘,但是重绘不一定引起回流

    重绘

    重绘是指一个元素的外观被改变了,背景颜色、文字颜色、边框颜色等。就会引起浏览器对某一部分的重画,但是并不会引起页面布局的改变。

    如何避免回流和重绘

    • 可以将需要多次修改的DOM元素设置display:none,操作完再显示。(因为隐藏元素不在render树内,因此修改隐藏元素不会触发回流重绘)
    • 用transform做形变和位移可以减少reflow
    • 操作完成后再显示 需要创建多个 DOM 节点时,使用 DocumentFragment 创建完后一次性的加入 document
    • 缓存 Layout 属性值,如:var left = elem.offsetLeft; 这样,多次使用 left 只产生一次回流
    • 尽量避免用 table 布局(table 元素一旦触发回流就会导致 table 里所有的其它元素回流)

    浏览器优化的建议

    • 样式文件应当在head标签中,而脚本文件在body结束前,这样可以防止阻塞的方式
    • 简化并优化CSS选择器,尽量将嵌套层减少到最小。
    • 不要一条条地改变样式,而要通过改变class,或者csstext属性,一次性地改变样式
    • 尽量用transform来做形变和位移
    • 先将元素设为display: none(需要1次重排和重绘),然后对这个节点进行100次操作,最后再恢复显示(需要1次重排和重绘)。这样一来,你就用两次重新渲染,取代了可能高达100次的重新渲染。
    • 只在必要的时候,才将元素的display属性为可见,因为不可见的元素不影响重排和重绘。另外,visibility : hidden的元素只对重绘有影响,不影响重排。