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


    前情提要:

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

    一条渲染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 加速,但是不能滥用
  • 相关阅读:
    springmvc log4j 配置
    intellij idea maven springmvc 环境搭建
    spring,property not found on type
    intellij idea maven 工程生成可执行的jar
    device eth0 does not seem to be present, delaying initialization
    macos ssh host配置及免密登陆
    centos7 搭建 docker 环境
    通过rest接口获取自增id (twitter snowflake算法)
    微信小程序开发体验
    gitbook 制作 beego 参考手册
  • 原文地址:https://www.cnblogs.com/liukuidashen/p/14169543.html
Copyright © 2020-2023  润新知