前言
以前写css和html和一些原生DOM操作,感觉写完就完事了。从来没有考虑过一些性能优化的问题,刚好最近学完了浏览器的事件循环和浏览器的工作流程。今天大家分享一些我刚学习到的前端小优化。
浏览器的工作流程
浏览器的渲染过程大致分为以下几个阶段:
- HTML解析:将HTML文档解析成DOM树。
- CSS解析:将CSS规则解析成CSSOM树。
- 合成渲染树:DOM树与CSSOM树结合,生成渲染树
- 布局计算:根据渲染树计算每个节点的几何位置和尺寸,形成布局树。
- 绘制阶段:将布局树转换为实际像素,绘制到屏幕上。
这一系列步骤高效协作,最终将静态的HTML和CSS代码转化为用户可见的动态页面。
这意味着css的复杂度是会影响到渲染树的生成进而影响浏览器的渲染速度。因此在css中我们需要简化选择器,避免使用过于复杂的选择器。
1- 避免使用 *(通配符) 选择器
有没有人开始学前端都和我一样都喜欢这样进行样式初始化的
*{
margin:0px;
padding:0px;
}
上面的代码虽然能实现所有标签的样式初始化,但是通配符选择器匹配页面上的每一个元素。在大型或结构复杂的网页中,这可能意味着成百上千甚至上万个元素。浏览器的CSS引擎在处理这样的选择器时,需要遍历整个DOM树,对每个元素进行检查和匹配,这无疑增加了计算负担,可能导致页面渲染变慢,尤其是初次加载时。
如果您需要初始化css的代码的话这个网站是个不错的选择:CSS Tools: Reset CSS (meyerweb.com)
2-避免直接使用标签选择器
请看下面这段代码做出你的选择:
<ul class="list">
<li class="list-item"></li>
</ul>
ul*10>li*10//这里代表着10个ul里面每个都拥有10个li标签
问:面对上面的html,你需要选中拥有list-item类名的li,请写出你认为效率最高的选择方法
- A选项 .list li
- B选项 .list .list-item
这题我认为效率最高的应该是B选项,下面是我的个人考量,大佬们有不同的见解也欢迎在评论区指出。
是从右往左进行读取匹配选择器,右边如果先读取到的如果是li
标签那么将会先匹配所有的li
标签节点,然后在往上寻找是父容器是否是 .list 类,应用css样式。所以在平常css的书写中,我们应当减少标签选择器的使用。使用类名或者是id 来进行标签的选择。
3-减少回流操作
减少回流操作之前,我先介绍一下,什么是回流:
回流是指浏览器为了重新渲染部分或全部文档而重新计算元素的位置和尺寸的过程。在回流过程中,浏览器会根据各种样式属性(如宽高、边距、填充、边框等)重新计算元素的位置和大小,然后绘制到屏幕上。(这是比较消耗时间的)
那什么时候会触发回流操作呢?
导致回流的原因有很多,常见的包括:
- DOM元素的添加、删除或修改:任何对DOM结构的改变都会导致回流。
- 样式计算:修改元素的样式属性(如宽高、边距、填充等)可能导致回流。
- 尺寸调整:调整浏览器窗口大小或添加/删除滚动条也会触发回流。
- 获取某些属性:读取某些属性(如
offsetWidth
、offsetHeight
、scrollTop
等)时,浏览器可能需要回流来确保返回最新的值。
看看下面这个案例你能找出几个优化点
for(let i=0;i<10000;i++){
document.querySelector('.list').innerHTML +=`<li>我是小丽</li>` ;
}
document.querySelector('.list')
应当提出到循环外面用变量保存,不然每次都需要重新进行选择- 减少操作原生dom的次数,不能像循环中一样每次循环操作一次。争取一次性操作完成,可以像下面这样
const list_item = document.querySelector('.list');
let str = "";
for(let i=0;i<10000;i++){
str+=`<li>我是小丽</li>` ;
}
list_item.innerHTML =str;
但是其实这里我推荐另外一种写法也是今天给大家介绍的猪脚之一,**createDocumentFragment
**文档碎片
4-文档碎片
DocumentFragment
是一个非常有用的 DOM 接口,它被用于创建一个轻量级的文档对象,它的独特之处在于它不会被渲染到页面中,但可以包含各种 DOM 节点。这种方法可以用于优化 DOM 操作,因为它可以减少页面上的回流和重绘次数。
上面的代码就可以写出下面这样
let content = document.createDocumentFragment();
const list_item = document.querySelector('.list');
for (let i = 0;i < 10000; i++) {
let li = document.createElement('li');
oSpan.innerHTML = '我是小丽';
content.appendChild(oSpan);
}
container.appendChild(content);
同样避免了dom节点的频繁操作,而且在语义结构上更加的丰富和完善。
结语
本次的分享就到这里了,希望对您有所收获,喜欢的话就点个关注或者是赞吧,谢谢- ̗̀(๑ᵔ⌔ᵔ๑)