浏览器如何减少 reflow/repaint
1.不要一条一条地修改 DOM 的样式。与其这样,还不如预先定义好 css 的 class,然后修改 DOM 的 className。
2)把 DOM 离线后修改。如:
- 使用 documentFragment 对象在内存里操作 DOM。
 - 先把 DOM 给 display:none (有一次 repaint),然后你想怎么改就怎么改。比如修改 100 次,然后再把他显示出来。
 - clone 一个 DOM 结点到内存里,然后想怎么改就怎么改,改完后,和在线的那个的交换一下。
 
3)不要把 DOM 结点的属性值放在一个循环里当成循环里的变量。不然这会导致大量地读写这个结点的属性。
4)尽可能的修改层级比较低的 DOM。当然,改变层级比较底的 DOM 有可能会造成大面积的 reflow,但是也可能影响范围很小。
5)为动画的 HTML 元件使用 fixed 或 absoult 的 position,那么修改他们的 CSS 是不会 reflow 的。
6)千万不要使用 table 布局。因为可能很小的一个小改动会造成整个 table 的重新布局。
- 1.优化JavaScript的执行效率
 - 1.1动画实现,避免使用setTimeout或setInterval,尽量使用requestAnimationFrame
 var start = null;
var element = document.getElementById('SomeElementYouWantToAnimate');
element.style.position = 'absolute'; function step(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start;
element.style.left = Math.min(progress / 10, 200) + 'px';
if (progress < 2000) {
window.requestAnimationFrame(step);
}
} window.requestAnimationFrame(step);1.2把耗时长的JavaScript代码放到Web Workers中去做
- JavaScript代码运行在浏览器的主线程上,与此同时,浏览器的主线程还负责样式计算、布局、绘制的工作,如果JavaScript代码运行时间过长,就会阻塞其他渲染工作,很可能会导致丢帧。
前面提到每帧的渲染应该在16ms内完成,但在动画过程中,由于已经被占用了不少时间,所以JavaScript代码运行耗时应该控制在3-4毫秒。
如果真的有特别耗时且不操作DOM元素的纯计算工作,可以考虑放到Web Workers中执行。 - 代码实现:var dataSortWorker = new Worker("sort-worker.js"); dataSortWorker.postMesssage(dataToSort); // 主线程不受Web Workers线程干扰 dataSortWorker.addEventListener('message', function(evt) { var sortedData = e.data; // Web Workers线程执行结束 // ... });
1.3把DOM元素的更新划分为多个小任务,分别在多个frame中去完成
由于Web Workers不能操作DOM元素的限制,所以只能做一些纯计算的工作,对于很多需要操作DOM元素的逻辑,可以考虑分步处理,把任务分为若干个小任务,每个任务都放到requestAnimationFrame中回调执行
var taskList = breakBigTaskIntoMicroTasks(monsterTaskList); requestAnimationFrame(processTaskList); function processTaskList(taskStartTime) {
var nextTask = taskList.pop(); // 执行小任务
processTask(nextTask); if (taskList.length > 0) {
requestAnimationFrame(processTaskList);
}
} - 2.降低样式计算的范围和复杂度
 - 2.1降低样式选择器的复杂度
尽量保持class的简短,或者使用Web Components框架。
.box:nth-last-child(-n+1) .title {
}
// 改善后
.final-box-title {
}
2.2减少需要执行样式计算的元素个数
由于浏览器的优化,现代浏览器的样式计算直接对目标元素执行,而不是对整个页面执行,所以我们应该尽可能减少需要执行样式计算的元素的个数
 - 3.避免大规模、复杂的布局
 3.1尽可能避免触发布局
当你修改了元素的属性之后,浏览器将会检查为了使这个修改生效是否需要重新计算布局以及更新渲染树,对于DOM元素的“几何属性”修改,比如width/height/left/top等,都需要重新计算布局。
- 3.2使用flexbox替代老的布局模型
 - 3.3避免强制同步布局事件的发生
 - 渲染屏幕的流程
 
- 首先是JavaScript脚本,然后是Style,然后是Layout,但是我们可以强制浏览器在执行JavaScript脚本之前先执行布局过程,这就是所谓的强制同步布局。
 requestAnimationFrame(logBoxHeight); // 先写后读,触发强制布局
function logBoxHeight() {
// 更新box样式
box.classList.add('super-big'); // 为了返回box的offersetHeight值
// 浏览器必须先应用属性修改,接着执行布局过程
console.log(box.offsetHeight);
} // 先读后写,避免强制布局
function logBoxHeight() {
// 获取box.offsetHeight
console.log(box.offsetHeight); // 更新box样式
box.classList.add('super-big');
}
在JavaScript脚本运行的时候,它能获取到的元素样式属性值都是上一帧画面的,都是旧的值。因此,如果你在当前帧获取属性之前又对元素节点有改动,那就会导致浏览器必须先应用属性修改,结果执行布局过程,最后再执行JavaScript逻辑。
3.4避免连续的强制同步布局发生
如果连续快速的多次触发强制同步布局,那么结果更糟糕。
比如下面的例子,获取box的属性,设置到paragraphs上,由于每次设置paragraphs都会触发样式计算和布局过程,而下一次获取box的属性必须等到上一步设置结束之后才能触发。- function resizeWidth() { // 会让浏览器陷入'读写读写'循环 for (var i = 0; i < paragraphs.length; i++) { paragraphs[i].style.width = box.offsetWidth + 'px'; } } // 改善后方案 var width = box.offsetWidth; function resizeWidth() { for (var i = 0; i < paragraphs.length; i++) { paragraphs[i].style.width = width + 'px'; } }
 - 4.简化绘制的复杂度、减少绘制区域
 - 绘制就是填充像素的过程,通常这个过程是整个渲染流程中耗时最长的一环,因此也是最需要避免发生的一环。
如果Layout被触发,那么接下来元素的Paint一定会被触发。当然纯粹改变元素的非几何属性,也可能会触发Paint,比如背景、文字颜色、阴影效果等。 - 5.优先使用渲染层合并属性、控制层数量
 5.1使用transform/opacity实现动画效果
使用transform/opacity实现动画效果,会跳过渲染流程的布局和绘制环节,只做渲染层的合并。
- 6.对用户输入事件的处理函数去抖动(移动设备)
 6.1避免使用运行时间过长的输入事件处理函数
理想情况下,当用户和页面交互,页面的渲染层合并线程将接收到这个事件并移动元素。这个响应过程是不需要主线程参与,不会导致JavaScript、布局和绘制过程发生。
但是如果被触摸的元素绑定了输入事件处理函数,比如touchstart/touchmove/touchend,那么渲染层合并线程必须等待这些被绑定的处理函数执行完毕才能执行,也就是用户的滚动页面操作被阻塞了,表现出的行为就是滚动出现延迟或者卡顿。
简而言之就是你必须确保用户输入事件绑定的任何处理函数都能够快速的执行完毕,以便腾出时间来让渲染层合并线程完成他的工作。
6.2避免在输入事件处理函数中修改样式属性
输入事件处理函数,比如scroll/touch事件的处理,都会在requestAnimationFrame之前被调用执行。
因此,如果你在上述输入事件的处理函数中做了修改样式属性的操作,那么这些操作就会被浏览器暂存起来,然后在调用requestAnimationFrame的时候,如果你在一开始就做了读取样式属性的操作,那么将会触发浏览器的强制同步布局操作。- 参考文章:https://www.jianshu.com/p/a32b890c29b1
 
浏览器如何减少 reflow/repaint的更多相关文章
- 如何优化你的JS脚本来减少reflow/repaint?
		
如何优化你的脚本来减少reflow/repaint?1. 避免在document上直接进行频繁的DOM操作,如果确实需要可以采用off-document的方式进行,具体的方法包括但不完全包括以下几种: ...
 - 浏览器渲染原理--reflow
		
Web页面运行在各种各样的浏览器当中,浏览器载入.渲染页面的速度直接影响着用户体验简单地说,页面渲染就是浏览器将html代码根据CSS定义的规则显示在浏览器窗口中的这个过程.先来大致了解一下浏览器都是 ...
 - ♫【网站优化】Reflow / Repaint
		
web移动开发最佳实践之js篇 浏览器的回流与重绘 by 张盛志 DOM性能瓶颈与Javascript性能优化 浏览器的渲染原理简介 其中一个跟浏览器有关的原因,那就是浏览器需要花时间.花精力去渲染. ...
 - 浏览器的回流与重绘 (Reflow & Repaint)
		
写在前面 在讨论回流与重绘之前,我们要知道: 浏览器使用流式布局模型 (Flow Based Layout). 浏览器会把HTML解析成DOM,把CSS解析成CSSOM,DOM和CSSOM合并就产生了 ...
 - 浏览器的重绘与回流(Reflow & Repaint)介绍
		
重绘 当页面元素样式改变不影响元素在文档流中的位置时(如background-color,border-color,visibility),浏览器只会将新样式赋予元素并进行重新绘制操作. 回流 当改变 ...
 - 介绍回流与重绘(Reflow & Repaint),以及如何进行优化?
		
前言 回流与重绘对于前端来说可以说是非常重要的知识点了,我们不仅需要知道什么是回流与重绘,还需要知道如何进行优化.一个页面从加载到完成,首先是构建DOM树,然后根据DOM节点的几何属性形成render ...
 - Reflow & Repaint
		
http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/ http://segmentfault.com/a/1190000002 ...
 - web前端优化手段
		
web前端优化手段有很多,同种的优化方式或许在不同的网络协议会南辕北辙,下面就自己结合工作经验和学习总结的一些手段总结 1.合并文件减小请求数:sprite图片的合成.合并脚本与样式. 2.减小文件的 ...
 - HTML(总结)
		
HTML 浏览器内核有哪些 Trident:IE Gecko:Firefox Webkit:Chrome Safari Presto:Opera(投奔Webkit) html5的一些新特性 1. 拖拽 ...
 
随机推荐
- CSS3 nth-of-type(n)选择器 last-of-type选择器 nth-last-of-type(n)选择器 CSS3 only-child选择器   only-of-type选择器
			
CSS3 nth-of-type(n)选择器 “:nth-of-type(n)”选择器和“:nth-child(n)”选择器非常类似,不同的是它只计算父元素中指定的某种类型的子元素.当某个元素中的子元 ...
 - File类常用方法和枚举
			
新建一个file对象: File f = new File("F:\\01.JAVA基础300集\\05_常用类\\122.File类的使用.mp4"); (文件路径也可以用&qu ...
 - 又联考了一场,感觉自己好菜啊,T2推出了公式但是不会逆元QAQ,难受啊!!!不过都确实是一道逆元的好题撒!
			
简单的玄学(random) 题目描述: 样例输入: 样例1: 3 2 样例2: 1 3 样例3: 4 3 样例输出: 样例1: 1 8 样例2: 1 1 样例3: 23 128 提示: 时间限制:10 ...
 - Python_013(面向对象概念)
			
一.面向对象 1.面向对象几个概念问题: a:类:具有相同属性和技能的一类事物.用代码表示就是,我类里面有一些静态变量和方法是大家共有的; b:对象:具体的类的表现.在代码中就是,调用类的方法或变量传 ...
 - hdu 5511 Minimum Cut-Cut——分类讨论思想+线段树合并
			
题目:http://acm.hdu.edu.cn/showproblem.php?pid=5511 题意:割一些边使得无向图变成不连通的,并且恰好割了两条给定生成树上的边.满足非树边两段一定在给定生成 ...
 - Favorite Donut
			
Favorite Donut Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) ...
 - 170820-关于JSP页面的知识点
			
1.JSP [1] 简介 > HTML - HTML擅长显示一个静态的网页,但是不能调用Java程序. > Servlet - Servlet擅长调用Java程序和后台进行交互,但是它不擅 ...
 - php函数名后冒号+数据类型(返回值类型限制/php新特性)
			
在PHP7,一个新的功能,返回类型声明已被引入.返回类型声明指定的一个函数返回值的类型. int float bool string interfaces array callable 对象实例 如下 ...
 - django中的url控制
			
1.django中的第一个控件:url控制 (路由分发) urls.py:请求路径与视图函数的之间的关系 步骤: 1.首先是要配置环境, 2.其次就是引路径 3.在视图的文件夹里面写相应的函 ...
 - Embedding理解与代码实现
			
https://blog.csdn.net/songyunli1111/article/details/85100616