浏览器重排与重绘详解


在了解浏览器的重排与重绘之前,我们来先了解一下浏览器的渲染机制。

浏览器的渲染机制

对于渲染,我们首先需要了解一个概念:设备刷新率

设备刷新率是设备屏幕渲染的频率,通俗一点就是,把屏幕当作墙,设备刷新率就是多久重新粉刷一次墙面。基本我们平常接触的设备,如手机、电脑,它们的默认刷新频率都是60FPS,也就是屏幕在1s内演染60次,约16.7ms渲染一次屏幕。

这就意味着,我们的浏览器最佳的渲染性能就是所有的操作在一帧16.7ms内完成,能否做到一帧内完成直接决定着渲染性,影响用户交互。

浏览器渲染的具体流程:

  • DOM树与CSSOM树合并后形成渲染树
  • 渲染树只包含渲染网页所需的节点
  • 布局计算每个对象的精确位置和大小。
  • 最后一步是绘制,使用最终渲染树将像素渲染到屏幕上。
    在这里插入图片描述

总结浏览器的渲染流程:

  • DOM树构建
  • CSSOM树构建
  • RenderObject树构建(呈现树)
  • 布局(为每个节点分配一个应出现在屏幕上的确切坐标)
  • 绘制

了解了浏览器的渲染机制后,我们来看看什么是重排与重绘。

重排reflow(回流)

reflow指的是重新计算页面的布局

某个节点reflow时会重新计算节点的尺寸和位置,而且还有可能触发其子节点、祖先节点和页面上的其他节点reflow。在这之后再触发一次repaint。

当render tree 中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建,这就称为回流。每个页面至少需要一次回流,就是在页面第一次加载的时候。

导致reflow的操作:

  • 调整窗口大小
  • 改变字体
  • 增加或者移除样式表
  • 内容变化,比如:hover(IE中为兄弟结点伪类的激活)
  • 操作class属性
  • 脚本操作DOM
  • 计算offsetWidth和offsetHeight属性(相对于父元素的边框的偏移量)
  • 设置style属性的值

重绘repaint

repaint或者redraw遍历所有的节点,检测各节点的可见性、颜色、轮廓等可见的样式属性,然后根据检测的结果更新页面的响应部分。

当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的(颜色,轮廓等),比如background-color。则就叫做重绘。

只触发重绘不触发重排的一些css属性:

  • color
  • border-style、border-radius
  • visibility(改变可见性)
  • text-decoration
  • background、background-image、background-position、background-repeat、background-size
  • outline、outline-color、outline-style、outline-width(输入框的边框颜色等)
  • box-shadow(阴影)

例如:

var bstyle=document.body.style;

bstyle.padding="20px";    //reflow,repaint
bstyle.backgroundColor="red";  //repaint
bstyle.fontSize="10px";  //reflow,repaint

需要知道的是,浏览器不会像上面一样,每改一次样式,它就reflow或repaint一次。一般来说,浏览器会把这样的操作积攒一批,然后做一次reflow,这又叫做异步reflow或增量异步reflow。但是,当遇到resize窗口操作,或改变了页面默认的字体时,对于这些操作,浏览器会马上reflow。

减少重排与重绘

重排和重绘在实际开发中是很难避免的,我们能做的就是尽量减少这种行为的发生。

具体方法:

  • js尽量少访问dom节点和css属性,尽量不要过多的频繁的去增加,修改,删除元素,因为这可能会频繁的导致页面reflow,可以先把该dom节点抽离到内存中进行复杂的操作然后再一次性display到页面上(进行一次重排和重绘)。(可以使用React,Vue的虚拟DOM)

  • 减少不必要的DOM层级(DOM depth)。改变DOM树中的一级会导致所有层级的改变,上至根部,下至被改变节点的子节点。这导致大量时间耗费在执行reflow上面。

  • 不要通过父级来改变子元素样式,最好直接改变子元素样式,改变子元素样式尽可能不要影响父元素和兄弟元素的大小和尺寸

  • 尽最通过class来设计元素样式,切忌用style多次操作单个属性

  • 尽可能的为产生动画的HTML元素使用fixed或absolute的position,那么修改他们的CSS是不会 reflow的。

  • **img标签要设置高宽,**以减少重绘重排

  • 把DOM离线后修改,如将一个dom脱离文档流,比如display:none,再修改属性,这里只发生一次回流。

  • 尽量用transform来做形变和位移,不会造成回流

  • 权衡速度的平滑。比如实现一个动画,以1个像素为单位移动这样最平滑,但reflow就会过于频繁,CPU很快就会被完全占用。如果以3个像素为单位移动就会好很多。

  • 不要用tables布局的另一个原因就是tables中某个元素一旦触发reflow就会导致table里所有的其它元素 reflow。在适合用table的场合,可以设置table-layout为auto或fixed

  • 避免不必要的复杂的CSS选择器,尤其是后代选择器(descendantselectors),因为为了匹配选择器将耗费更多的CPU

    补充:

    visibility:hidden是隐藏元素,但元素仍占据着布局空间(即将其渲染成一个空框);

    display:none将元素从渲染树中完全移除,元素既不可见,也不是布局的组成部分。

    display:none会触发reflow,而visibility:hidden(隐藏)只会触发repaint,因为没有发生位置变化。

总结

重排:元素的尺寸变了、位置变了

重绘:元素的颜色、背景、边框、轮廓变了,但是,元素的几何尺寸没有变。

Reflow的成本比Repaint的成本高得多的多。DOM Tree里的每个结点都会有reflow方法,一个结点的reflow很有可能导致子结点,其至父点以及同级结点的reflow。在一些高性能的电脑上也许还没什么,但是如果reflow发生在手机上,那么这个过程是非常痛苦和耗电的。

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值