回流和重绘——周分享

浏览器的回流与重绘 (Reflow & Repaint)

image.png
image.png
  • 浏览器使用流式布局模型 (Flow Based Layout)。指的就是处于流中靠后位置元素通常不会影响靠前位置元素的几何特征,因此布局可以按从左至右、从上至下的顺序遍历文档。对Render Tree的计算通常只需要遍历一次就可以完成。但是也有例外情况,比如 HTML 表格的计算就需要不止一次的遍历。

  • 浏览器会把HTML解析成DOM,把CSS解析成CSSOM,DOM和CSSOM合并就产生了Render Tree。

  • 有了RenderTree,我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置,最后把节点绘制到页面上。

一句话:回流必将引起重绘,重绘不一定会引起回流。就比如改变个div的背景颜色并不会触发回流,可是改变了浏览器窗口大小或者改变了这个div的宽度或位置就触发了回流。


回流

通过构造渲染树(Render Tree),我们将可见DOM节点以及它对应的样式结合起来,可是我们还需要计算它们在设备视口内的确切位置和大小,这个计算的阶段就是回流

重绘

通过构造渲染树(Render Tree)和回流阶段,我们知道了哪些节点是可见的,以及可见节点的样式和具体的几何信息(位置、大小),那么我们就可以将渲染树的每个节点都转换为屏幕上的实际像素,这个阶段就叫做重绘节点。

当代浏览器的优化
  • 回流比重绘的代价要更高。
    有时即使仅仅回流一个单一的元素,它的父元素以及任何跟随它的元素也会产生回流。
clientWidth、clientHeight、clientTop、clientLeft
offsetWidth、offsetHeight、offsetTop、offsetLeft
scrollWidth、scrollHeight、scrollTop、scrollLeft
width、height
getComputedStyle()
getBoundingClientRect()

正常浏览器会维护一个队列,把所有引起回流和重绘的操作放入队列中,如果队列中的任务数量或者时间间隔达到一个阈值的,浏览器就会将队列清空,进行一次批处理,这样可以把多次回流和重绘变成一次。
当你访问上述的属性或方法时,队列中可能会有影响到这些属性或方法返回值的操作,浏览器便会强行清空队列,确保你拿到的值是最精确的。

  • 最小化回流和重绘
const el = document.getElementById('element');
el.style.padding = '2px';
el.style.borderLeft = '2px';
el.style.width = '30px';
·········

有多个样式属性被修改了,每一个都会影响元素的几何结构,引起回流、有其他代码访问了布局信息(上文中的会触发回流的布局信息),那么就会导致多次重绘。因此,可以通过添加整个CSS的类来合并所有的改变然后依次处理。


const el = document.getElementById('element');
el.className += ' active';

<style>
.active{
    padding: 2px;
    borderLeft: 2px;
    width: 30px;
}
</style>
const el = document.getElementById('test');
  • css contain 属性允许当前元素和它的内容尽可能的独立于 DOM 树的其他部分。隔离指定节点的样式、布局和渲染。

  • 元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。避免频繁读取会引发回流/重绘的属性。

  • 对具有复杂动画的元素使用绝对定位,使它脱离文档流,在文档流中的动画会引起父元素及后续元素频繁回流。而比起考虑如何减少回流重绘,我们更期望的是,根本不要回流重绘。所以css3硬件加速(GPU加速)才是我们所期望的。 使用transform、opacity、filters等这些属性是不会引起回流重绘 。

  • 避免触发同步布局事件

function test() {
    for (let i = 0; i < 100; i++) {
        i.style.width = `${box.offsetWidth}px`;
    }
}

这段代码看上去是没有什么问题,可是其实会造成很大的性能问题。立即回流是同步的在每次循环的时候,都读取了box的一个offsetWidth属性值,然后利用它来更新标签的width属性。这就导致了每一次循环的时候,都会强制浏览器刷新队列。才能响应本次循环的样式读取操作。

const width = box.offsetWidth;
function test() {
    for (let i = 0; i < 100; i++) {
        i.style.width =`${width}px';
    }
}

可以定义一个变量来缓存box的offsetWidth属性值,避免循环中回流。

总结一下:
会引起元素位置变化的就会回流(Reflow),如窗口大小改变、字体大小改变、以及元素位置改变,都会引起周围的元素改变他们以前的位置;
不会引起位置变化的,只是在以前的位置进行改变背景颜色等,只会重绘(Repaint);

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容