當了解web訪問原理后,與前端工程師或頁面重構師工作更為關系密切的應該是瀏覽器,WEB 頁面運行在各種各樣的瀏覽器當中,瀏覽器載入、渲染頁面的速度直接影響着用戶體驗, 特別是瀏覽器渲染頁面的原理,頁面渲染就是瀏覽器將 HTML 代碼根據 CSS 定義的規則顯示在瀏覽器窗口中的這個過程,理解了原理就更會容易理解前端優化的一些准則。
主要過程:(主要參考文章:http://www.webskys.com/artilc/228.html)
1. 用戶輸入網址(假設是個 HTML 頁面,第一次訪問,無緩存情況),瀏覽器向服務器發出HTTP請求,服務器返回 HTML 文件; (善用緩存,減少HTTP請求,減輕服務器壓力)
2. 瀏覽器載入 HTML 代碼,發現 <head> 內有一個 <link> 引用外部 CSS 文件,則瀏覽器立即發送CSS文件請求,獲取瀏覽器返回的CSS文件; (CSS文件合並,減少HTTP請求)
3. 瀏覽器繼續載入 HTML 中 <body> 部分的代碼,並且 CSS 文件已經拿到手了,可以開始渲染頁面了; (CSS文件需要放置最上面,避免網頁重新渲染)
4. 瀏覽器在代碼中發現一個 <img> 標簽引用了一張圖片,向服務器發出請求。此時瀏覽器不會等到圖片下載完,而是繼續渲染后面的代碼; (圖片文件合並,減少HTTP請求)
5. 服務器返回圖片文件,由於圖片占用了一定面積,影響了后面段落的排布,因此瀏覽器需要回過頭來重新渲染這部分代碼; (最好圖片都設置尺寸,避免重新渲染)
6. 瀏覽器發現了一個包含一行 JavaScript 代碼的 <script> 標簽,會立即運行該js代碼; (script最好放置頁面最下面)
7. js腳本執行了語句,它令瀏覽器隱藏掉代碼中的某個 <div>,突然就少了一個元素,瀏覽器不得不重新渲染這部分代碼; (頁面初始化樣式不要使用js控制)
8. 終於等到了 </html> 的到來,瀏覽器淚流滿面……
9. 等等,還沒完,用戶點了一下界面中的“換膚”按鈕,JavaScript 讓瀏覽器換了一下 <link> 標簽的 CSS 路徑;
10. 瀏覽器召集了在座的各位 <div><span><ul><li> 們,“大伙兒收拾收拾行李,咱得重新來過……”,瀏覽器向服務器請求了新的CSS文件,重新渲染頁面。
瀏覽器每天就這么來來回回跑着,要知道不同的人寫出來的 HTML 和 CSS 代碼質量參差不齊,說不定哪天跑着跑着就掛掉了。
好在這個世界還有這么一群人——頁面重構工程師,平時挺不起眼,也就幫視覺設計師們切切圖啊改改字,其實背地里還是干了不少實事的。
影響頁面渲染速度主要有:reflow(回流)和repaint(重繪)
reflow(回流)
說到頁面為什么會慢?那是因為瀏覽器要花時間、花精力去渲染,尤其是當它發現某個部分發生了點變化影響了布局,需要倒回去重新渲染, 該過程稱為reflow(回流)。
reflow 幾乎是無法避免的。現在界面上流行的一些效果,比如樹狀目錄的折疊、展開(實質上是元素的顯 示與隱藏)等,都將引起瀏覽器的 reflow。鼠標滑過、點擊……只要這些行為引起了頁面上某些元素的占位面積、定位方式、邊距等屬性的變化,都會引起它內部、周圍甚至整個頁面的重新渲 染。通常我們都無法預估瀏覽器到底會 reflow 哪一部分的代碼,它們都彼此相互影響着。
repaint(重繪)
如果只是改變某個元素的背景色、文 字顏色、邊框顏色等等不影響它周圍或內部布局的屬性,將只會引起瀏覽器 repaint(重繪)。
repaint 的速度明顯快於 reflow(在IE下需要換一下說法,reflow 要比 repaint 更緩慢)。
盡量避免reflow(回流)
reflow(回流)是導致DOM腳本執行低效的關鍵因素之一。頁面上任何一個結點觸發reflow,都會導致它的子結點及祖先結點重新渲染。
在哪些情況下會導致reflow發生:
- 改變窗囗大小
- 改變文字大小
- 添加/刪除樣式表
- 內容的改變,如用戶在輸入框中敲字
- 激活偽類,如:hover (IE里是一個兄弟結點的偽類被激活)
- 操作class屬性
- 腳本操作DOM
- 計算offsetWidth和offsetHeight
- 設置style屬性
reflow是不可避免的,只能將reflow對性能的影響減到最小。
- 盡可能限制reflow的影響范圍。需要改變元素的樣式,不要通過父級元素影響子元素。最好直接加在子元素上。
- 通過設置style屬性改變結點樣式的話,每設置一次都會導致一次reflow。所以最好通過設置class的方式。
- 實現元素的動畫,它的position屬性應當設為fixed或absolute,這樣不會影響其它元素的布局。
- 權衡速度的平滑。比如實現一個動畫,以1個像素為單位移動這樣最平滑,但reflow就會過於頻繁,CPU很快就會被完全占用。如果以3個像素為單位移動就會好很多。
- 不要用tables布局的另一個原因就是tables中某個元素一旦觸發reflow就會導致table里所有的其它元素reflow。在適合用table的場合,可以設置table-layout為auto或fixed,這樣可以讓table一行一行的渲染,這種做法也是為了限制reflow的影響范圍。
- 很多情況下都會觸發reflow,如果css里有expression,每次都會重新計算一遍。
- 減少不必要的 DOM 層級(DOM depth)。改變 DOM 樹中的一級會導致所有層級的改變,上至根部,下至被改變節點的子節點。這導致大量時間耗費在執行 reflow 上面。
- 避免不必要的復雜的 CSS 選擇器,尤其是后代選擇器(descendant selectors),因為為了匹配選擇器將耗費更多的 CPU。
深入學習:現代瀏覽器工作原理