今天我要將關注點放到頁面渲染以及其重要性上。雖然已經有不少文章提到過這個主題了,但大部分信息都是零碎的片斷。爲了思考這件事情,我須要研究不少信息的來源。這也就是爲何我以爲我應該寫這篇文章的緣由。我相信這篇文章對新手會頗有用,而且對想刷新和鞏固他們已經瞭解的東西的高手也一樣適用。javascript
渲染應該從最開始當頁面佈局被定義時就進行優化,樣式和腳本在頁面渲染中扮演着很是重要的角色。專業人員知道一些技巧以免一些性能問題。php
這篇文章不會深刻研究瀏覽器的技術細節,而是提供一些通用的原則。不一樣瀏覽器引擎工做原理不一樣,這就使特定瀏覽器的學習更加複雜。css
咱們從瀏覽器渲染頁面的大概過程開始提及:java
當在頁面上修改了一些不須要改變定位的樣式的時候(好比background-color,border-color,visibility),瀏覽器只會將新的樣式從新繪製給元素(這就叫一次「重繪」或者「從新定義樣式」)。jquery
當頁面上的改變影響了文檔內容、結構或者元素定位時,就會發生重排(或稱「從新佈局」)。重排一般由如下改變觸發:web
瀏覽器盡最大努力限制重排
的過程僅覆蓋已更改的元素的區域。舉個例子,一個 position 爲 absolue 或 fixed 的元素的大小變化隻影響它自身和子孫元素,而對一個 position 爲 static 的元素作一樣的操做就會引發全部它後面元素的重排。瀏覽器
另外一個優化就是當運行一段Jjavascript 代碼的時候,瀏覽器會將一些修改緩存起來,而後當代碼執行的時候,一次性的將這些修改執行。舉例來講,這段代碼會觸發一次重繪和一次重排:緩存
var $body = $('body'); $body.css('padding', '1px'); // 重排, 重繪 $body.css('color', 'red'); // 重繪 $body.css('margin', '2px'); // 重排, 重繪 // 實際上只有一次重排和重繪被執行。
如上面所說,訪問一個元素的屬性會進行一次強制重排。若是咱們給上面的代碼加上一行讀取元素屬性的代碼,這個狀況就會出現:服務器
var $body = $('body'); $body.css('padding', '1px'); $body.css('padding'); // 這裏讀取了一次元素的屬性,一次強制重排就會發生。 $body.css('color', 'red'); $body.css('margin', '2px');
上面這段代碼的結果就是,進行了兩次重排。所以,爲了提升性能,你應該講讀取元素屬性的代碼組織在一塊兒(細節的例子能夠看JSBin上的代碼)。babel
有一種狀況是必須觸發一次強制重排的。例如:給元素改變同一個屬性兩次(好比margin-left),一開始設置100px,沒有動畫,而後經過動畫的形式將值改成50px。具體能夠看例子,固然,我在這裏會講更多的細節。
咱們從一個有transition的CSS class開始:
.has-transition { -webkit-transition: margin-left 1s ease-out; -moz-transition: margin-left 1s ease-out; -o-transition: margin-left 1s ease-out; transition: margin-left 1s ease-out; }
而後進行實現:
//咱們的元素默認有"has-transition"屬性 var $targetElem = $('#targetElemId'); //刪除包含transition的class $targetElem.removeClass('has-transition'); // 當包含transition的class已經沒了的時候,改變元素屬性 $targetElem.css('margin-left', 100); // 再將包含transition的class添加回來 $targetElem.addClass('has-transition'); // 改變元素屬性 $targetElem.css('margin-left', 50);
上面的實現沒有按照指望的運行。全部的修改都被瀏覽器緩存了,只在上面這段代碼的最後纔會執行。咱們須要的是一次強制重排,咱們能夠經過進行如下修改來實現:
//刪除包含transition的class $(this).removeClass('has-transition'); // 改變元素屬性 $(this).css('margin-left', 100); //觸發一次強制重排,從而使變化了的class或屬性可以當即執行。 $(this)[0].offsetHeight; // offsetHeight僅僅是個例子,其餘的屬性也能夠奏效。 // 再將包含transition的class添加回來 $(this).addClass('has-transition'); // 改變元素屬性 $(this).css('margin-left', 50);
如今這段代碼如咱們所指望的運行了。
彙總了一些有用的信息,我建議如下幾點:
class選擇器: .class
標籤: div
相鄰的兄弟元素:a + i
父元素選擇器: ul > li
通配符選擇器: *
僞類和僞元素: a:hover ,你應該記住瀏覽器處理選擇器是從右向左的,這也就是爲何最右面的選擇器會更快——#id或.class。div * {...} // bad .list li {...} // bad .list-item {...} // good #list .list-item {...} // good
想了解更多的細節,能夠看一下這些文章:
但願這篇文章可以對你有所幫助!
原文連接: frontendbabel 翻譯: 伯樂在線 - Moejser
譯文連接: http://blog.jobbole.com/72692/