重排、重绘
提及这两个概念很多老哥第一反应肯定是:重排必然会引起重绘,但重绘不会引起重排,因为网上大多数资料都是这么说的。
重排真的一定会引起重绘么?首先先来看几个概念
重排
dom节点几何属性/位置等发生变化时,需要重新进行样式计算,然后生成布局树,重新计算位置信息/大小
重绘
dom节点的颜色属性/透明度绘制属性发生变化,需要重新绘制
页面渲染流水线
页面第一次加载时,整个渲染过程大致如下
可以看出正常情况下,页面渲染过程先经历重排,然后再重绘。
只重排不重绘
如下动画
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
html,
body {
width: 100%;
margin: 0;
padding: 0;
}
.box {
width: 100%;
height: 200px;
border: 1px solid red;
position: relative;
box-sizing: border-box;
}
.child {
background: hotpink;
width: 50px;
height: 50px;
animation: play 16ms infinite;
/* 开启硬件加速 */
transform: translate3d(0,0,0);
}
@keyframes play {
0% {
left: 0;
}
100% {
left: 400px
}
}
</style>
</head>
<body>
<div class="box">
<div class="child">child</div>
</div>
<div class="box">
<div class="child">child</div>
</div>
<div class="box">
<div class="child">child</div>
</div>
<div class="box">
<div class="child">child</div>
</div>
</body>
</html>
使用transform
属性让浏览器为参与动画的节点child
分别创建单独的合成层
,合成层
作为纹理上传存储在GPU
中,当通过css修改child
节点的几何属时,会进行: 样式计算
->重排(loyout)
->从GPU取出缓存的纹理(位图),不用重绘
-> 图层合成
-> 合成图片展示
重排然后重绘
上面的动画去掉transform: translate3d(0,0,0);
后,child
没有了单独的合成层
,没有了缓存,所以每一帧都需要重新绘制
结论
-
可见
重排
不一定就会重绘
两者没有必然的因果联系 -
常说的
硬件加速
之所以提升动画性能,是因为创建了单独的合成层
,可以将合成层的纹理缓存在GPU中,动画播放时,只需读取纹理在合成线程进行图层的合成,避免重排、重绘占频繁占用渲染主线程导致的卡顿将动画由
left
改成translateX
后:```html @keyframes play { 0% { transform: translateX(0); } 100% { transform: translateX(400px); } } ```
动画播放过程只有图层的合成,主线程完全空闲