前言
以前寫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節點的頻繁操作,而且在語義結構上更加的豐富和完善。
結語
本次的分享就到這里了,希望對您有所收獲,喜歡的話就點個關注或者是贊吧,謝謝-???(?????)