了解及优化页面回流和重绘

题记:web开发经常会听到回流和重绘这两个词,最近看了一些文档,简单记录下自己对这两个概念的理解以及怎么尽可能避免回流和重绘,提高页面渲染速度。

概念

  • 回流
    浏览器的渲染过程中,计算DOM节点在视口内的显示/隐藏,确切位置和大小,这个计算的阶段就是回流。

  • 重绘
    是一个元素外观的改变(自身的宽高,布局,及显示或隐藏没有改变)所触发的浏览器行为,例如改变vidibility、background-color等属性。浏览器会根据元素的新属性重新绘制,这个阶段就是重绘。

  • 根据两个的概念我们可以得出:

回流必定触发重绘,而重绘不一定触发回流

优化回流和重绘

  • 减少回流和重绘的次数
<style type="text/css">
     .change { width: 10px; height: 10px; }
</style>
<script type="text/javascript">
     $(document).ready(function () {
         var el = $('#id');
         //1
         el.css('width', '10px');
         el.css('height', '10px');
         //2
         el.addClass('change');
         //3
         el.style.cssText += 'width: 10px; height: 10px;';
     });
</script>

以上3种做法,我这里弱弱的推荐第2,3种,避免第1种。

  • 限制回流和重绘的范围
    先说说图层吧

css 中有一个重要的概念的就是 “划分图层”。

在页面加载完dom之后,浏览器会根据自身制定的一些特殊css 属性对页面进行划分为一个个图层。例如:一些有着 position: absolute 属性的元素他们会被浏览器归纳到一个图层中,而另外一些 position: fixed 的元素也会被浏览器归纳到另外一个图层中,还有一些例如:transform: translateZ(0)… 这些属性都是视浏览器厂商制定的

图层的优点就是:当一个元素在自己图层内发生变化的时候它的回流和重绘只会在图层内部发生,从而减少了浏览器对于重绘与回流的运算量。

那图层内部究竟干了什么呢?

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

然后,对它们生成图形和位置

紧跟着,将每个节点绘制填充到图层位图中

再然后,图层作为纹理发送到GPU 上

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

图层虽好,但是如果滥用图层的话就会让页面因为进行了太多合并运算导致页面卡顿。

所以说,图层的用途应该让给那些经常要进行位置结构,布局变换的元素去使用。例如轮播图

那我们如创建一个图层呢?

就拿chrome 来说,创建一个图层要有以下其中一个条件:

1:一个dom 元素拥有 3d 或 透视变换的css 属性(persepective, transform)

2:video 标签

3:拥有3d 上下文或加速 2d 上下文的 canvas 节点

4:混合插件 flash

5:自己做的opacity 动画 或 使用一个动画 webkit 变换的元素

6:拥有 translate3d 或 translateZ 这两会使 GPU 加速的属性

7:一个包含复合层子节点的元素。(有点绕,可以这样想:其实本身整个网页页面就是一个图层,html 标签下包含着若干的标签 head, body,… 这样便满足了这个条件了)

8:元素有一个其 z-index 比它低的兄弟节点。由于 z-index 控制的是元素上下层的关系,所以当上下层关系变换的时候就需要一个图层去渲染,因此满足这个条件的元素也会被创建一个图层

但是在我的实验中发现第7 和 8是没有被变成图层的,不知道为嘛…

那如果我们使用属性又有那些可替换的属性可以优化回流与重绘呢
一共有以下9点:

  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. 不要使用table 布局,因为table 的每一个行甚至每一个单元格的样式更新都会导致整个table 重新布局

  7. 动画的速度按照业务按需决定

  8. 对于频繁变化的元素应该为其加一个 transform 属性,对于视频使用video 标签

  9. 必要时可以开启 GPU 加速,但是不能滥用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值