1)瀏覽器會(huì)解析三個(gè)東西:
一個(gè)是HTML/SVG/XHTML蒲牧,事實(shí)上纯赎,Webkit有三個(gè)C++的類對(duì)應(yīng)這三類文檔傅蹂。解析這三種文件會(huì)產(chǎn)生一個(gè)DOM Tree。(上圖中的DOM區(qū)塊)
CSS刨秆,解析CSS會(huì)產(chǎn)生CSS規(guī)則樹凳谦。(上圖中的CSSDOM區(qū)塊)
Javascript,腳本衡未,主要是通過DOM API和CSSOM API來操作DOM Tree和CSS Rule Tree.(上圖中的RENDER TREE區(qū)塊)
2)解析完成后尸执,瀏覽器引擎會(huì)通過DOM Tree 和 CSS Rule Tree 來構(gòu)造 Rendering Tree家凯。注意:
- Rendering Tree 渲染樹并不等同于DOM樹,因?yàn)橐恍┫馠eader或display:none的東西就沒必要放在渲染樹中了如失。
- CSS 的 Rule Tree主要是為了完成匹配并把CSS Rule附加上Rendering Tree上的每個(gè)Element绊诲。也就是DOM結(jié)點(diǎn)。也就是所謂的Frame褪贵。建立CSS Rule Tree是需要比照著DOM Tree來的掂之。
- 計(jì)算每個(gè)Frame(也就是每個(gè)Element)的位置,這又叫l(wèi)ayout和reflow過程脆丁。
3)最后通過調(diào)用操作系統(tǒng)Native GUI的API繪制世舰。
注意:CSS匹配HTML元素是一個(gè)相當(dāng)復(fù)雜和有性能問題的事情。所以槽卫,你就會(huì)在N多地方看到很多人都告訴你跟压,DOM樹要小,CSS盡量用id和class歼培,千萬不要過渡層疊下去
渲染
- 計(jì)算CSS樣式
構(gòu)建Render Tree
Layout – 定位坐標(biāo)和大小震蒋,是否換行,各種position, overflow, z-index屬性 ……
正式開畫
注意:上圖流程中有很多連接線躲庄,這表示了Javascript動(dòng)態(tài)修改了DOM屬性或是CSS屬會(huì)導(dǎo)致重新Layout喷好,有些改變不會(huì),就是那些指到天上的箭頭读跷,比如,修改后的CSS rule沒有被匹配到禾唁,等效览。
這里重要要說兩個(gè)概念,一個(gè)是Reflow荡短,另一個(gè)是Repaint丐枉。這兩個(gè)不是一回事。
1.Repaint——屏幕的一部分要重畫掘托,比如某個(gè)CSS的背景色變了瘦锹。但是元素的幾何尺寸沒有變。
Reflow——意味著元件的幾何尺寸變了闪盔,我們需要重新驗(yàn)證并計(jì)算Render Tree弯院。是Render Tree的一部分或全部發(fā)生了變化。這就是Reflow泪掀,或是Layout听绳。(HTML使用的是flow based layout,也就是流式布局异赫,所以椅挣,如果某元件的幾何尺寸發(fā)生了變化头岔,需要重新布局,也就叫reflow)reflow 會(huì)從<html>這個(gè)root frame開始遞歸往下鼠证,依次計(jì)算所有的結(jié)點(diǎn)幾何尺寸和位置峡竣,在reflow過程中,可能會(huì)增加一些frame量九,比如一個(gè)文本字符串必需被包裝起來适掰。
2.Reflow的成本比Repaint的成本高得多的多。DOM Tree里的每個(gè)結(jié)點(diǎn)都會(huì)有reflow方法娩鹉,一個(gè)結(jié)點(diǎn)的reflow很有可能導(dǎo)致子結(jié)點(diǎn)攻谁,甚至父點(diǎn)以及同級(jí)結(jié)點(diǎn)的reflow。在一些高性能的電腦上也許還沒什么弯予,但是如果reflow發(fā)生在手機(jī)上戚宦,那么這個(gè)過程是非常痛苦和耗電的。
所以锈嫩,下面這些動(dòng)作有很大可能會(huì)是成本比較高的受楼。
- 當(dāng)你增加、刪除呼寸、修改DOM結(jié)點(diǎn)時(shí)艳汽,會(huì)導(dǎo)致Reflow或Repaint
當(dāng)你移動(dòng)DOM的位置,或是搞個(gè)動(dòng)畫的時(shí)候对雪。
當(dāng)你修改CSS樣式的時(shí)候河狐。
當(dāng)你Resize窗口的時(shí)候(移動(dòng)端沒有這個(gè)問題),或是滾動(dòng)的時(shí)候瑟捣。
當(dāng)你修改網(wǎng)頁(yè)的默認(rèn)字體時(shí)馋艺。
注:display:none會(huì)觸發(fā)reflow,而visibility:hidden只會(huì)觸發(fā)repaint迈套,因?yàn)闆]有發(fā)現(xiàn)位置變化捐祠。
基本上來說,reflow有如下的幾個(gè)原因:
- Initial桑李。網(wǎng)頁(yè)初始化的時(shí)候踱蛀。
Incremental。一些Javascript在操作DOM Tree時(shí)贵白。
Resize率拒。其些元件的尺寸變了。
StyleChange禁荒。如果CSS的屬性發(fā)生變化了俏橘。
Dirty。幾個(gè)Incremental的reflow發(fā)生在同一個(gè)frame的子樹上圈浇。
示例
<pre>var bstyle = document.body.style; // cache
bstyle.padding = "20px"; // reflow, repaint
bstyle.border = "10px solid red"; // 再一次的 reflow 和 repaint
bstyle.color = "blue"; // repaint
bstyle.backgroundColor = "#fad"; // repaint
bstyle.fontSize = "2em"; // reflow, repaint
// new DOM element - reflow, repaint
document.body.appendChild(document.createTextNode('dude!'));</pre>
當(dāng)然寥掐,我們的瀏覽器是聰明的靴寂,它不會(huì)像上面那樣,你每改一次樣式召耘,它就reflow或repaint一次百炬。一般來說,瀏覽器會(huì)把這樣的操作積攢一批污它,然后做一次reflow剖踊,這又叫異步reflow或增量異步reflow。但是有些情況瀏覽器是不會(huì)這么做的衫贬,比如:resize窗口德澈,改變了頁(yè)面默認(rèn)的字體,等固惯。對(duì)于這些操作梆造,瀏覽器會(huì)馬上進(jìn)行reflow。
減少reflow/repaint
1.不要一條一條地修改DOM的樣式葬毫。與其這樣镇辉,還不如預(yù)先定義好css的class,然后修改DOM的className贴捡。
2.把DOM離線后修改忽肛。
3.不要把DOM結(jié)點(diǎn)的屬性值放在一個(gè)循環(huán)里當(dāng)成循環(huán)里的變量。不然這會(huì)導(dǎo)致大量地讀寫這個(gè)結(jié)點(diǎn)的屬性烂斋。
4.盡可能的修改層級(jí)比較低的DOM屹逛。當(dāng)然,改變層級(jí)比較底的DOM有可能會(huì)造成大面積的reflow汛骂,但是也可能影響范圍很小罕模。
5.為動(dòng)畫的HTML元件使用fixed或absoult的position,那么修改他們的CSS是不會(huì)reflow的香缺。
6.千萬不要使用table布局。因?yàn)榭赡芎苄〉囊粋€(gè)小改動(dòng)會(huì)造成整個(gè)table的重新布局歇僧。
文章出處點(diǎn)這里