一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情。
如何避免
CSS
- 避免使用 table 布局。
- 尽可能在 DOM 树的最末端改变 class。
- 避免设置多层内联样式。
- 将动画效果应用到 position 属性为 absolute 或 fixed 的元素上。
- 避免使用 CSS 表达式(例如:calc())。
Javascript
- 避免频繁操作样式,最好一次性重写 style 属性,或者将样式列表定义为 class 并一次性更改 class 属性。
// 优化前
const el = document.getElementById('test');
el.style.borderLeft = '1px';
el.style.borderRight = '2px';
el.style.padding = '5px';
// 优化后,一次性修改样式,这样可以将三次重排减少到一次重排
const el = document.getElementById('test');
el.style.cssText += '; border-left: 1px ;border-right: 2px; padding: 5px;'
- 避免频繁操作 DOM,创建一个
documentFragment
,在它上面应用所有 DOM 操作,最后再把它添加到文档中。 - 也可以先为元素设置 display: none,操作结束后再把它显示出来。因为在
display 属性为 none 的元素上进行的 DOM 操作不会引发回流和重绘
。 - 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个
变量缓存起来
。 - 对具有复杂
动画的元素使用绝对定位
,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
DocumentFragment
DocumentFragment 表示一个没有父级文件的最小文档对象。它被当做一个轻量版的 Document 使用,用于存储已排好版的或尚未打理好格式的XML片段。最大的区别是因为DocumentFragment不是真实DOM树的一部分,它的变化不会引起DOM树的重新渲染的操作(reflow) ,且不会导致性能等问题。
使用DocumentFragment能解决直接操作DOM引发大量回流的问题,比如我们要给ul添加五个li节点,区别就像这样:
直接操作DOM,回流五次:
使用DocumentFragment一次性添加,回流一次:
<body>
<ul id="list"></ul>
<ul id="list1"></ul>
</body>
//使用documentFragment添加节点
console.time("time")
let list = document.querySelector("#list"),
fragment = document.createDocumentFragment(), // documentFragment
n = 50000;
while(n--){
fragment.appendChild(document.createElement("li"));
};
list.appendChild(fragment);
console.timeEnd("time")
//直接操作DOM添加节点
console.time("time1")
let list1 = document.querySelector("#list1"),
i = 50000;
while(i--){
list1.appendChild(document.createElement("li"))
};
console.timeEnd("time1")