前端性能优化(二)——浅谈回流与重绘
前言
本文主要对回流与重绘进行一个简介,并且列举出在实际开发中哪些操作可能会造成回流重绘。如若有问题,请大家多多指教。话不多说,开冲!
回流
当我们对 DOM 的修改引发了 DOM 几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,浏览器需要重新计算元素的几何属性(其他元素的几何属性和位置也会因此受到影响),然后再将计算的结果绘制出来。这个过程就是回流(也叫重排),所以回流是产生的最根本原因是dom渲染问题。
重绘
重绘:当我们对 DOM 的修改导致了样式的变化、却并未影响其几何属性(比如修改了颜色或背景色)时,浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式(跳过了上图所示的回流环节)。这个过程叫做重绘。产生的原因也是因为dom的修改
什么操作会产生回流和重绘?
通过上面的介绍,可以清晰的看出回流和重绘的关系。重绘不一定导致回流,回流一定会导致重绘,如果硬要说二者区别,我想的是,回要做的事情比重绘要做的事情更多,所需要的开销更多。所以在日常开发中,要尽量的吧回流重绘次数降到最低。
回流“导火索”
回流可以说是“牵一发而动全身”
首先,当一个dom元素的几何属性发生变化时,和他相关的所有节点属性(父子节点,兄弟节点)都会放生变化(几何属性),进行重新计算,会带来大量的额计算量。
常见的几何属性有 width、height、padding、margin、left、top、border 等等(常用的基本上就这些,还有其他的也记不住,因为实在是太多了)
其次,获取一些特定的属性,也会造成回流。例如:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight。
因为这些属性进行获取值,是需要实时计算的。因此浏览器为了获取这些东西,也会进行回流操作
重绘“导火索”
相比回流,重绘的导火索就更容易分辨————只要是不触发回流,但又触发了样式改变的 DOM 操作,都会引起重绘,比如背景色、文字色、可见性(可见性这里特指形如visibility: hidden这样不改变元素位置和存在性的、单纯针对可见性的操作,注意与display:none进行区分)等。
如何规避回流与重绘?
实际开发中,我们要尽量的去规避,但是很多时候又不得不用。当无法 避免时,我们就应该去更“聪明”的去使用。
例如:有时我们想要通过多次计算得到一个元素的布局位置,我们就可以将“导火索”缓存起来,避免重复的改动,即:“先循环,再赋值”
// 缓存offsetLeft与offsetTop的值
const el = document.getElementById('el')
let offLeft = el.offsetLeft, offTop = el.offsetTop
// 在JS层面进行计算
for(let i=0;i<10;i++) {
offLeft += 10
offTop += 10
}
// 一次性将计算结果应用到DOM上
el.style.left = offLeft + "px"
el.style.top = offTop + "px"
还可以使用一个类名 去合并公共样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.basic_style {
width: 100px;
height: 200px;
border: 10px solid red;
color: red;
}
</style>
</head>
<body>
<div id="container"></div>
<script>
const container = document.getElementById('container')
container.classList.add('basic_style')
</script>
</body>
</html>
还可以进行DOM离线化操作,就是通过display:none.将其从页面上“拿掉”,那么我们的后续操作,将无法触发回流与重绘.虽然拿掉一个元素再把它放回去,也会触发一次昂贵的回流,但我们把它拿下来了,后续不管我操作这个元素多少次,每一步的操作成本都会非常低
小结
之所以考虑dom上的操作,是因为并不是所有浏览器都是聪明的,而我们并不知道用户会使用什么样的浏览器。如果不手动做优化,那么一个页面在不同的环境下就会呈现不同的性能效果。所以养成一个开开发习惯,从根源解决问题,才是最明智的。
(我就是我,全网最菜的前端——痴心。有缘下次更新见。)