回流和重绘的区别和避免

2,239 阅读3分钟

回流(Reflow) 

当Render Tree中部分或全部元素的尺寸、结构或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程成为回流

导致回流的操作

  • 页面首次渲染 
  • 浏览器窗口大小发生变化 
  • 元素尺寸或位置发生改变 
  • 元素内容变化(文字数量和图片大小等等) 
  • 元素字体大小变化 
  • 添加或者删除可见的DOM元素 
  • 激活伪类元素 
  • 查询某些属性或调用某些方法 

导致回流的属性和方法 

  • clientWidth、clientHeight、clientTop、clientLeft 
  • offsetWidth、offsetHeight、offsetTop、offsetLeft 
  • scrollWidth、scrollHeight、scrollTop、scrollLeft 
  • scrollIntoView()、scrollIntoViewIfNedded() 
  • getComputedStyle()
  • getBoundingClientRect() 
  • scrollTo()

重绘 

当页面中元素央视的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘

回流必将引起重绘,重绘不一定会引起回流

避免回流和重绘方法

 减少回流、重绘其实就是需要减少对render tree的操作,并减少对一些style信息的请求,尽量利用好浏览器的优化策略 

  1. 避免操作DOM,创建一个documentFragment或div,在它上面应用所有DOM操作,最后再把它添加到window.document。也可以在一个display:none的元素上进行操作,最终把它显示出来。因为display:none上的DOM操作不会引发回流和重绘。 

  2. 让要操作的元素进行"离线处理",处理完后一起更新,这里所谓的"离线处理"即让元素不存在于render tree中。如读取offsetLeft等属性。 

  3. 尽可能在DOM树的末端改变class ,尽可能在DOM树的里面改变class,可以限制回流的范围,使其影响尽可能少的节点。 

  4. 避免设置多层内联样式,因为每一个都会造成回流,样式合并在一个外部类,这样当该元素的class属性被操作时,只会产生一个reflow。 

  5. 将需要多次回流的元素position属性设为absolute或fixed,这样该元素就会脱离文档流,它的变化不会影响其他元素变化。比如动画效果应用到position属性为absolute或fixed的元素上。 

  6. 牺牲平滑度换取速度,动画元素每次移动3像素可能在非常快的机器上看起来平滑度低了,但它不会导致CPU在较慢的机器和移动设备中抖动 

  7. 避免使用table布局,在布局完全建立之前,table需要很多关口,table是可以影响之前已经进入的DOM元素的显示的元素。即使一些小的变化和会导致table中所有其他节点回流。   

  8. 避免使用css的JavaScript表达式,该规则较过时,但是个好主意。因为每次都需要重新计算文档,或部分文档、回流。 回流时,浏览器会使渲染树中受影响的部分失效,然后重新构造这部分的render树。完成回流之后浏览器会重新布局、绘制受影响的部分到屏幕中,该过程就是重绘。所以回流必定会引起重绘,但重绘不一定引起回流。 每个页面至少需要一次回流,就是页面第一次加载时。回流变化涉及到部分页面(或整个页面)的布局。一个元素的回流导致其所有子元素以及DOM中紧随其后的祖先元素和其子元素都发生回流。  

    执行顺序 
    先回流后重绘