拾人牙慧理解並整理之
直奔主題,要考慮到頁面性能優化,必須得理解瀏覽器的渲染機制才行。
1、原理
渲染引擎在這里就不展開了,可自行搜索解決。下面說說渲染流程,大致是這樣的:
瀏覽器在接收到服務器返回的html頁面后,
瀏覽器開始構建DOM TREE,遇到CSS樣式會構建CSS RULER TREE,
遇到javascript會通過DOM API和CSSOM API來操作DOM Tree和CSS Rule Tree,解析完成后,
瀏覽器引擎會通過DOM Tree 和 CSS Rule Tree 來構造 Rendering Tree(渲染樹),
最后,渲染樹構建完成后就是” 布局“處理,也就是確定每個節點在屏幕上的確切顯示位置。 下一個步驟是 繪制 —— 遍歷渲染樹並用UI后端層將每一個節點繪制出來。
用一張圖來表示
另外,在構建相應的樹形結構時,會發生阻礙:
在構建DOM樹時,
- HTML的響應流被阻塞在了網絡中
- 有未加載完的腳本
- 遇到了script節點,但是此時還有未加載完的樣式文件
例子:
1 <html> 2 <body> 3 <link rel="stylesheet" href="example.css"> 4 <div>Hi there!</div> 5 <script> 6 document.write('<script src="other.js"></scr' + 'ipt>'); 7 </script> 8 <div>Hi again!</div> 9 <script src="last.js"></script> 10 </body> 11 </html>
首先,解析器遇到了example.css,並將它從網絡中下載下來。下載樣式表的過程是耗時的,但是解析器並沒有被阻塞,繼續往下解析。接下來,解析器遇到script標簽,但是由於樣式文件沒有加載下來,阻塞了該腳本的執行(上面已指出)。解析器(構建DOM TREE和 CSS RULER TREE)被阻塞住,不能繼續往下解析。
同樣的,因為渲染樹是DOM Tree 和 CSS Rule Tree 來構造,所以此時,渲染樹的構建也被阻塞,同時Hi there!也就 不能被繪制(painting->display)到頁面中,
繪制的條件是,渲染樹構建完成並遇到阻塞就會觸發繪制。
接下來,一旦example.css文件加載完成,內聯的腳本執行完之后,解析器就會立即被other.js阻塞住。一旦解析器被阻塞,瀏覽器就會收到繪制請求,"Hi there!"也就顯示在了頁面上。同理,當other.js加載完成之后,解析器繼續向下解析,解析器遇到last.js之后會被阻塞,然后瀏覽器收到了另一個繪制請求,"Hi again!"就顯示在了頁面上。最后last.js會被加載,並且會被執行。
另外,CSS在頁面的渲染上是從上到下,從右到左的機制,
例如,div#username p span.red{color:red;},瀏 覽器的查找順序如下:先查找html中所有class=’red’的span元素,找到后,再查找其父輩元素中是否有p元素,再判斷p的父元素中是否有id為 username的div元素,如果都存在則CSS匹配上。
例如如下代碼:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title></title> 5 <meta charset="utf-8"> 6 <style type="text/css"> 7 .red{ color:red; } 8 .blue{ color:blue; } 9 </style> 10 </head> 11 <body> 12 <p class="red blue">這是一段文字</p> 13 </body> 14 </html>
字體還是會顯示為藍色,


瀏覽器從右到左進行查找的好處是為了盡早過濾掉一些無關的樣式規則和元素。firefox稱這種查 找方式為keyselector(關鍵字查詢),所謂的關鍵字就是樣式規則中最后(最右邊)的規則,上面的key就是span.red。
所以在我們命名class類名的時候,盡量重用樣式。
以上參考的資料有:瀏覽器的渲染原理簡介
2、頁面性能優化的方法:
把原理理解的差不多了再來看看常見的優化方法,
1、DOM結構不要復雜,不必要的標簽堅決不要,例如:<div class="clearfix"></div>這樣一個清除浮動的標簽,雖然很好用,但是會增加瀏覽器的渲染,我們可以用別的方法代替啊,例如增加偽元素after,為了兼容IE67也是可以利用IE67的一些特有的屬性來清除浮動的,比如zoom:1;是不是?
2、少引用css,js文件,少增加圖片的請求次數,很常見的css sprites。
3、少用濾鏡,少用hack,少用position:absolute;。
在這里我想問,為什么要少用絕對定位?為什么?請點這里詳解
4、使用簡寫樣式,如background,margin,padding等。
5、不要在ID選擇器和class選擇器前 使用標簽名 例如:div.box { color: #f00; }; 直接 可以 用類名, .box { color:#f00;} 這樣瀏覽器找到這個class后 就不用再匹配是否存在div標簽.從而提高了渲染效率。當然同一級的 有不同的樣式可以這樣寫,但是不建議這樣。
6、css的層級關系不要太深 用class直接代替多余的層級元素。例如 .box .box-con .box-list li { line-height: 24px; } 這么長。。。增加代碼量減小開發效率。剛也說了,css渲染是從上到下,從右到左的。所以直接這樣寫就可以了.box-list li { line-height: 24px; };
7、平鋪背景圖片不要過小,影響渲染速率。
8、float使用要謹慎。為什么這么說?這就得深入float了解了,自己接下來多了解了解吧。
最后,第一次比較認真的寫文章,有點亂,無頭無尾的,希望自己越寫越好。
我想用這個來結束這篇文章,我覺得很生動的描述瀏覽器在接收到html后解析渲染出來的過程,此處引用。。。
1.用戶輸入網址(假設是個html頁面,並且是第一次訪問),瀏覽器向服務器發出請求,服務器返回html文件;
2.瀏覽器開始載入html代碼,發現<head>標簽內有一個<link>標簽引用外部CSS文件;
3.瀏覽器又發出CSS文件的請求,服務器返回這個CSS文件;
4.瀏覽器繼續載入html中<body>部分的代碼,並且CSS文件已經拿到手了,可以開始渲染頁面了;
5.瀏覽器在代碼中發現一個<img>標簽引用了一張圖片,向服務器發出請求。此時瀏覽器不會等到圖片下載完,而是繼續渲染后面的代碼;
6.服務器返回圖片文件,由於圖片占用了一定面積,影響了后面段落的排布,因此瀏覽器需要回過頭來重新渲染這部分代碼;
7.瀏覽器發現了一個包含一行Javascript代碼的<script>標簽,趕快運行它;
8.Javascript腳本執行了這條語句,它命令瀏覽器隱藏掉代碼中的某個<div> (style.display=”none”)。突然少了這么一個元素,瀏覽器不得不重新渲染這部分代碼;
9.終於等到了</html>的到來,瀏覽器淚流滿面……
10.等等,還沒完,用戶點了一下界面中的“換膚”按鈕,Javascript讓瀏覽器換了一下<link>標簽的CSS路徑;
11.瀏覽器召集了在座的各位<div><span><ul><li>們,“大伙兒收拾收拾行李,咱得重新來過……”,瀏覽器向服務器請求了新的CSS文件,重新渲染頁面。
此處參考: