zoukankan      html  css  js  c++  java
  • 五、重绘与回流

    css性能让javascript变慢?

    会的,频繁触发重绘与回流,会导致UI频繁渲染,最终导致js变慢。

    有两个线程:一个线程JavaScript解析,一个线程是UI渲染,这两个其实是互斥的两个线程。

    当javascript 线程运行的时候 ui 线程则会中止暂停,反之亦然。

    那这是为什么呢?

    原因是,当ui 线程运行对页面进行渲染的时候 js 脚本难免会涉及到页面视图上的一些样式的改变,为了使这个改变更加准确 js 脚本只好等待ui 线程渲染完成的时候才去执行。

    所以当一个页面的元素样式改动频繁的时候ui 线程就会持续渲染,造成js 代码反应慢半拍,卡顿的情况。

    回流

    • 当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)
    • 当页面布局和几何属性改变时就需要回流
    • 触发页面重布局的属性:
      1、盒子模型相关属性会触发重布局:width ,height,padding,margin,display,border-width,border,min-heigh。

       2、定位属性及浮动也会触发重布局:top,bottom,left,right,position,float,clear

       3、改变节点内部文字结构也会触发重布局:text-align,overflow-y,font-weight,overflow,font-family,line-height,vertival-align,white-space,font-size

    重绘

    • 当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘。
    • 只触发重绘的属性:
      color
      border-style
      border-radius
      visibility
      text-decoration
      background
      background-image
      background-position
      background-repeat
      background-size
      outline-color
      outline
      outline-style
      outline-width
      box-shadow

    总结:回流必将引起重绘,而重绘不一定会引起回流

    现在我们知道了那些属性会触发回流,那如何避免回流呢?

    其实有两个方法:

    第一,不使用以上能触发图层回流的属性,

    第二,建立一个图层,让回流在这些图层里面进行,限制回流和重绘的范围,减少浏览器的运算工作量

    新建DOM的过程

    1. 获取DOM后分割为多个图层
    2. 对每个图层的节点计算样式结果(Recalculate style--样式重计算)
    3. 为每个节点生成图形和位置(Layout--回流和重布局)
    4. 将每个节点绘制填充到图层位图中(Paint Setup和Paint--重绘)
    5. 图层作为纹理上传至GPU
    6. 符合多个图层到页面上生成最终屏幕图像(Composite Layers--图层重组)

    将频繁重绘回流的DOM元素单独作为一个独立图层,那么这个DOM元素的重绘和回流的影响只会在这个图层中。

    Chrome创建自动创建图层的条件

    • 3D或透视变换(perspective transform)CSS属性
    • 使用加速视频解码的<video>节点
    • 拥有3D(WebGL)上下文或加速的2D上下文的<canvas>节点
    • 混合插件(如Flash)
    • 对自己的opacity做CSS动画或使用一个动画webkit变换的元素
    • 拥有加速CSS过滤器的元素
    • 元素有一个包含复合层的后代节点(一个元素拥有一个子元素,该子元素在自己的层里)
    • 元素有一个z-index较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)

    如何手动创建图层l两种方法:

    • will-change:transform
    • transform:translateZ(0)

    Chrome浏览器的more tools下面的Layers能查看图层信息,rendering能查看浏览器页面正在重绘的元素。

    用图层可以减少重绘和回流,但是图层会有合成的消耗,因此两者之间需要一个balance!

    实战优化点:

    1. 用translate替代top改变
    2. 用opacity(不会触发回流,更不会触发重绘,没有paint的过程,因为paint的过程是生成图层,但是opcacity实际上是直接改变的图层的alpha通道,所以不涉及图层的重绘)替代visibility(会触发重绘但是不会触发回流),但是要同时有translate3d 或 translateZ 这些可以创建的图层的属性存在才可以阻止回流
    3. 不要一条一条地修改 DOM 的样式,预先定义好 class,然后修改 DOM 的 className

    4. 把 DOM 离线后修改,比如:先把 DOM 给 display:none (有一次 Reflow),然后你修改100次,然后再把它显示出来,如果确实需要用 js 对 dom 设置多条样式那么可以将这个dom 先隐藏,然后再对其设置

    5. 不要把 DOM 结点的属性值放在一个循环里当成循环里的变量。浏览器有一个回流的缓冲机制,即多个回流会保存在一个栈里面,当这个栈满了浏览器便会一次性触发所有样式的更改且刷新这个栈。但是如果你多次获取这些元素的实际样式,浏览器为了给你一个准确的答案便会不停刷新这个缓冲栈,导致页面回流增加。所以为了避免这个问题,应该用一个变量保存在循环体外。

    6. 不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局
    7. 动画实现的速度的选择。动画的时间间隔短,动画连续,但是不断的回流重绘影响性能,动画的时间长,动画卡顿,性能会好点。
    8. 对于动画新建图层,对于频繁变化的元素应该为其加一个 transform 属性,对于视频使用video 标签
    9. 启用 GPU 硬件加速,通过设置transform:translateZ(0);transform: translate3d(0,0,0)

  • 相关阅读:
    字符串的格式化操作
    了解格式化输出,字符串和编码
    面试题2
    面试题1
    设计算法1
    C++ STL容器的理解
    网络是怎样连接的-路由器的附加功能
    网络是怎样连接的-路由器的包转发操作(下)
    网络是怎样连接的-路由器的包转发操作(上)
    网络是怎样连接的-交换机的包转发操作
  • 原文地址:https://www.cnblogs.com/QianDingwei/p/11028362.html
Copyright © 2011-2022 走看看