• 前端:性能优化之回流和重绘


    前情提要:

    浏览器渲染一个网页的时候会启用两条线程:

    一条渲染javascript 脚本,另一条渲染 UI即css 样式的渲染。

    两条线程是互斥的。

    当javascript 线程运行的时候 UI线程则会中止暂停,相反当UI线程运行的时候javascript线程也会中途停止。

    为什么互斥呢?

    因为当ui线程运行,对页面进行渲染的时候,js脚本难免会影响页面视图的样式发生改变,为了使页面样式改变更加准确,js脚本需要等待UI线程渲染完成的时候,再去执行。

    所以当一个页面的元素样式发生频繁改动的时候,UI 线程就会持续渲染,导致js 代码反应慢半拍、卡顿这种现象出现。

    一、回流和重绘究竟为何物?

    1、回流:当render tree 的一部分或全部的元素因改变了自身的宽高、布局、显示或隐藏,或者元素内部的文字结构发生变化,导致需要重新构建页面的时候,回流就产生了。

      1)触发回流的css 属性有这些:

      • 盒子模型相关属性会触发重布局。
      • 定位属性及浮动也会触发重布局
      • 改变节点内部文字结构也会触发重布局。          2)width 宽度                                  top                                        text-align  文本对齐方式  

         height 高度                                 bottom                                 font-weight 字体宽度 

         padding 内边距                           left                                       line-height 行高   

         margin   外边距                           right                                     vertival-align 垂直方向对齐方式  

         display   显示框类型                    position                                font-size 字体大小

                border    外边框线                       float                                      white-space 设置如何处理元素内的空白。

                                        over-flow-y  垂直方向溢出隐藏  

           2)如何避免回流?

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

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

      3)css 中有一个重要的概念—— "划分图层"。

    在页面加载完dom之后,浏览器会根据自身制定的一些特殊css 属性对页面进行划分为一个个图层


    例如:

    • position: absolute 属性的元素会被浏览器集中归纳到一个图层中,
    • position: fixed 的元素也会被浏览器集中归纳到另外一个图层中
    • 还有一些例如:transform: translateZ(0).... 也会被浏览器集中归纳到另外一个图层中

      4} 图层内部做了什么

    1、对图层里面的节点做回流和重布局运算,计算出他们的样式

    2、生成图形和位置

    3、将每个节点绘制填充在图层位图中

    4、将涂层作为纹理发送到GPU

    5、将所有的图层合并,显示在浏览器的页面上

                 总结:滥用图层会让页面进行了太多的合并运算而导致页面卡顿。所以图层的用途应该让那些经常要进行位置结构,布局变换的元素去使用。例如轮播图。

    2、重绘:当一个元素自身的宽高,布局,及显示或隐藏没有改变,而只改变了元素的外观风格的时候,就会产生重绘

    通过知道回流和重绘的定义,我们得知了一个结论,回流必定触发重绘,而重绘不一定触发回流

    触发重绘的有这些:
    • color                             字体颜色
    • border-style                 外边框线颜色
    • border-radius               圆角
    • visibility                        规定元素是否可见 
    • text-decoration            文本修饰符
    • background                  背景属性
    • background-image      背景图像
    • background-position   背景图定位
    • background-repeat      背景图去重复
    • background-size           背景图大小
    • outline-color                 设置点状轮廓的颜色
    • outline                           设置 4 个边框的样式:
    • outline-style                  设置轮廓的样式:
    • outline-width                设置元素整个轮廓的宽度
    • box-shadow                  设置盒子阴影

    二、如何优化回流和重绘?

    1. 用transform 代替 top,left ,margin-top, margin-left... 这些位移属性
    2. 用opacity 代替 visibility,但是要同时有translate3d 或 translateZ 这些可以创建的图层的属性存在才可以阻止回流,如果不加 transform: translateZ(0) 配合opacity的话还是会产生回流的,而只用visibility 就只会产生重绘不会产生回流,而  opacity 加上 transform: translateZ/3d  这个属性之后便不会发生回流和重绘了
    3. 不要使用 js 代码对dom 元素设置多条样式,选择用一个 className 代替之。
    4. 如果确实需要用 js 对 dom 设置多条样式那么可以将这个dom 先隐藏,然后再对其设置
    5. 不要在循环内获取dom 的样式例如:offsetWidth, offsetHeight, clientWidth, clientHeight... 这些。浏览器有一个回流的缓冲机制,即多个回流会保存在一个栈里面,当这个栈满了浏览器便会一次性触发所有样式的更改且刷新这个栈。但是如果你多次获取这些元素的实际样式,浏览器为了给你一个准确的答案便会不停刷新这个缓冲栈,导致页面回流增加。
    6. 所以为了避免这个问题,应该用一个变量保存在循环体外。
    7. 不要使用table 布局,因为table 的每一个行甚至每一个单元格的样式更新都会导致整个table 重新布局
    8. 动画的速度按照业务按需决定
    9. 对于频繁变化的元素应该为其加一个 transform 属性,对于视频使用video 标签
    10. 必要时可以开启 GPU 加速,但是不能滥用
  • 相关阅读:
    安卓界面基本组件------计时器
    安卓界面组件----时间日期拾取器
    安卓界面组件----列表视图
    安卓组件------列表选择框
    Redis 开启远程访问
    收集的一个关于大批量插入数据的代码
    Server.MapPath和Request.PhysicalApplicationPath的异同
    C#中使用正则表达式验证电话号码、手机号、身份证号、数字和邮编
    cocos2d-x3.2在xcode6.1下的 环境搭建
    STL源码剖析(适配器)
  • 原文地址:https://www.cnblogs.com/LcxWeb/p/14168405.html
Copyright © 2020-2023  润新知