翻譯如下:
網頁渲染必須在非常早的階段進行,這個階段可以早到頁面布局剛剛定型。因為樣式和腳本都對網頁渲染有關鍵影響。因此,專業的開發人員必須知道壹些技巧,以避免在實踐中出現性能問題。
本文將不研究瀏覽器內部的詳細機制,而是提出壹些通用規則。畢竟不同的瀏覽器引擎有不同的工作機制,這無疑會讓開發者對瀏覽器特性的研究更加復雜。
瀏覽器如何渲染網頁?
首先,我們來回顧壹下瀏覽器在渲染網頁時的動作:
根據來自服務器的HTML代碼形成文檔對象模型(DOM)。
加載和解析樣式以形成CSS對象模型。
在文檔對象模型和CSS對象模型之上,創建壹個由壹組要渲染的對象組成的渲染樹(在Webkit中,這些對象被稱為渲染器或渲染對象,而在Gecko中,它們被稱為“框架”。呈現樹反映了文檔對象模型的結構,但不包含不可見的元素,如標簽或display:none屬性。在渲染樹中,每個文本字符串都表示為壹個獨立的渲染器。每個渲染對象都包含其對應的DOM對象或文本塊,以及計算出的樣式。換句話說,渲染樹是文檔對象模型的直觀顯示。
對於渲染樹上的每個元素,計算其坐標,這稱為布局。瀏覽器使用流方法,壹個元素的布局只需要傳遞壹次,但是表格元素需要傳遞多次。
最後,渲染樹上的元素最終顯示在瀏覽器中,這個過程叫做“繪畫”。
當用戶與網頁交互時,或者腳本程序改變或修改網頁時,由於網頁的內部結構發生了變化,上面提到的壹些操作會被重復。
重畫
當改變不影響元素在網頁中的位置的元素的樣式時,例如背景顏色、邊框顏色和可見性,瀏覽器將只使用新的樣式重繪元素壹次(這是重繪,或重建樣式)。
重新整理
當改變影響文本的內容或結構,或元素的位置時,就會發生重排或重排。這些變化通常由以下事件觸發:
DOM操作(元素添加、刪除、修改或元素順序的改變);
內容更改,包括表單字段中的文本更改;
CSS屬性的計算或更改;
添加或刪除樣式表;
更改“類”的屬性;
瀏覽器窗口的操作(縮放、滾動);
偽類激活(:懸停)。
瀏覽器如何優化渲染?
瀏覽器試圖將重繪/重建限制在已更改元素的區域。例如,對於具有固定或絕對位置的元素,其大小更改只會影響元素本身及其子元素。但是,靜態定位的元素的大小變化將觸發所有後續元素的重新流動。
另壹種優化技術是,當運行幾段JavaScript代碼時,瀏覽器會緩存這些更改,然後在代碼運行後應用這些更改。例如,以下代碼只會觸發重構和重繪:
var $ body = $(' body ');
$body.css('padding ',' 1px ');//回流,重畫
$body.css('color ',' red ');//重畫
$body.css('margin ',' 2px ');//回流,重畫
//實際只會發生1 reflow和return但是,如上所述,改變元素的屬性會觸發強制重排。如果我們在上面的代碼塊中添加壹行代碼來訪問元素的屬性,就會發生這種情況。
var $ body = $(' body ');$body.css('padding ',' 1px ');$ body . CSS(' padding ');//讀取壹個屬性,壹個強制回流$body.css('color ',' red ');$body.css('margin ',' 2px ');
結果,重排發生了兩次。因此,您應該將訪問元素屬性的所有操作組織在壹起,以優化網頁的性能。(妳可以在JSBin中找到更詳細的例子。)
有時候,妳不得不觸發壹個強制重排。例如,我們必須將同壹個屬性(如左邊距)分配給同壹個元素兩次。壹開始應該設置為100px,不會帶動效果。然後,必須通過轉場改成50px。妳現在可以在JSbin上學習這個例子,但是我將在這裏更詳細地介紹它。
首先,我們創建壹個帶有過渡效果的CSS類:。has-transition {-Webkit-transition:margin-left 1 sease-out;-moz-transition:margin-left 1s緩出;-o-transition:margin-left 1s緩出;過渡:邊距-左側1s緩出;}
然後繼續執行://our有“has-transition”類的元素by default var $ target elem = $(' # target elemid ');
//刪除過渡類
$ target elem . remove class(' has-transition ');
//更改期望轉換關閉的屬性,因為該類不存在
//不再是了
$targetElem.css('margin-left ',100);
//把過渡類放回去
$ target elem . add class(' has-transition ');
//更改屬性
$targetElem.css('margin-left ',50);然而,這種實現是行不通的。所有更改都被緩存,並且只在代碼塊的末尾執行。我們需要的是強制性的重新安排,這可以通過以下變化來實現:
//移除過渡類$(this)。remove class(' has-transition ');
//更改屬性
$(這個)。css('左邊距',100);
//觸發強制回流,以便立即應用類/屬性中的更改
$(this)[0]。偏高;//舉個例子,其他屬性也可以
//把過渡類放回去
$(這個)。add class(“has-transition”);
//更改屬性
$(這個)。css('左邊距',50);現在代碼按預期執行。
關於性能優化的實用建議
綜合現有信息,我提出以下建議:
創建有效的HTML和CSS文件,不要忘記註明文檔的編碼方式。樣式應該包含在標簽中,腳本代碼應該添加在標簽的末尾。
盡量簡化和優化CSS選擇器(使用CSS預處理器的開發人員幾乎忽略了這壹點),將嵌套保持在最低限度。以下是CSS選擇器的性能排名(從最快開始)
1.識別器:#id
2.類別:。班級
3.標簽:div
4.相鄰兄弟選擇器:a+i
5.父類選擇器:ul & gt裏
6.通用選擇器:*
7.屬性選擇:輸入[type="text"]
8.偽類和偽元素:a:hover妳要記住瀏覽器是從右向左處理選擇器的,所以最右邊的選擇器應該是最快的:#id或者。class: div * {...}//壞。列表項目{...}//good # list。緩存所有內容,包括元素屬性和對象(如果它們被重用的話)。在做復雜操作時,最好使用“隔離”元素,這些元素可以在以後添加到DOM中(所謂“隔離”元素就是從DOM中分離出來,只存儲在內存中的元素)。
2.如果您使用jQuery來選擇元素,請遵循jQuery選擇器的最佳實踐。
3.為了改變元素的樣式,修改“類”的屬性是有效的方法之壹。在進行這種更改時,您在DOM呈現樹中的位置越深越好(這也有助於將邏輯與表示分離)。
4.盡量只給有絕對或固定位置的元素添加動畫效果。
5.使用滾動時禁用復雜的懸停效果(例如,在中添加壹個額外的非懸停類)。讀者可以讀壹篇關於這個問題的文章。
想了解更多細節,還可以看看這兩篇文章:
1,瀏覽器是如何工作的?
2、渲染:重畫、重排/重新布局、重新樣式