瀏覽器渲染頁面流程

瀏覽器內(nèi)核拿到內(nèi)容后拜银,渲染步驟大致可以分為以下幾步:

  1. 解析HTML凛忿,構(gòu)建DOM樹

  2. 解析CSS膘流,生成CSS規(guī)則樹

  3. 合并DOM樹和CSS規(guī)則榨乎,生成render樹

  4. 布局render樹(Layout/reflow)盔夜,負責(zé)各元素尺寸负饲、位置的計算

  5. 繪制render樹(paint),繪制頁面像素信息

  6. 瀏覽器會將各層的信息發(fā)送給GPU喂链,GPU會將各層合成(composite)返十,顯示在屏幕上

如下圖:


browser_rending.png

HTML解析,構(gòu)建DOM

整個渲染步驟中衩藤,HTML解析是第一步吧慢。
簡單的理解,這一步的流程是這樣的:
瀏覽器解析HTML赏表,構(gòu)建DOM Tree
解析HTML到構(gòu)建出DOM當(dāng)然過程可以簡述如下:

Bytes → characters → tokens → nodes → DOM

譬如假設(shè)有這樣一個HTML頁面:(以下部分的內(nèi)容出自參考來源检诗,修改了下格式)

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet">
    <title>Critical Path</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg"></div>
  </body>
</html>

瀏覽器的處理如下:


browser_parse_html.png

列舉其中的一些重點過程:

  1. Conversion轉(zhuǎn)換:瀏覽器將獲得的HTML內(nèi)容(Bytes)基于他的編碼轉(zhuǎn)換為單個字符

  2. Tokenizing分詞:瀏覽器按照HTML規(guī)范標準將這些字符轉(zhuǎn)換為不同的標記token。每個token都有自己獨特的含義以及規(guī)則集

  3. Lexing詞法分析:分詞的結(jié)果是得到一堆的token瓢剿,此時把他們轉(zhuǎn)換為對象逢慌,這些對象分別定義他們的屬性和規(guī)則

  4. DOM構(gòu)建:因為HTML標記定義的就是不同標簽之間的關(guān)系,這個關(guān)系就像是一個樹形結(jié)構(gòu)一樣
    例如:body對象的父節(jié)點就是HTML對象间狂,然后段略p對象的父節(jié)點就是body對象

最后的DOM樹如下:


browser_parse_dom.png

生成CSS規(guī)則

同理攻泼,CSS規(guī)則樹的生成也是類似。簡述為:

Bytes → characters → tokens → nodes → CSSOM

譬如style.css內(nèi)容如下:

body { font-size: 16px }
p { font-weight: bold }
span { color: red }
p span { display: none }
img { float: right }

那么最終的CSSOM樹就是:


browser_parse_cssom.png

構(gòu)建渲染樹

當(dāng)DOM樹和CSSOM都有了后,就要開始構(gòu)建渲染樹了

一般來說忙菠,渲染樹和DOM樹相對應(yīng)的何鸡,但不是嚴格意義上的一一對應(yīng)

因為有一些不可見的DOM元素不會插入到渲染樹中,如head這種不可見的標簽或者display: none等

整體來說可以看圖:


browser_parse_rendertree.png

渲染

有了render樹牛欢,接下來就是開始渲染骡男,基本流程如下:


browser_rendingprocess.jpg

圖中重要的四個步驟就是:

  1. 計算CSS樣式

  2. 構(gòu)建渲染樹

  3. 布局,主要定位坐標和大小傍睹,是否換行隔盛,各種position overflow z-index屬性

  4. 繪制,將圖像繪制出來

然后拾稳,圖中的線與箭頭代表通過js動態(tài)修改了DOM或CSS吮炕,導(dǎo)致了重新布局(Layout)或渲染(Repaint)

這里L(fēng)ayout和Repaint的概念是有區(qū)別的:

  • Layout,也稱為Reflow访得,即回流龙亲。一般意味著元素的內(nèi)容、結(jié)構(gòu)震鹉、位置或尺寸發(fā)生了變化俱笛,需要重新計算樣式和渲染樹

  • Repaint,即重繪传趾。意味著元素發(fā)生的改變只是影響了元素的一些外觀之類的時候(例如迎膜,背景色,邊框顏色浆兰,文字顏色等)磕仅,此時只需要應(yīng)用新樣式繪制這個元素就可以了.

回流的成本開銷要高于重繪,而且一個節(jié)點的回流往往回導(dǎo)致子節(jié)點以及同級節(jié)點的回流簸呈, 所以優(yōu)化方案中一般都包括榕订,盡量避免回流。

什么會引起回流蜕便?

1.頁面渲染初始化

2.DOM結(jié)構(gòu)改變劫恒,比如刪除了某個節(jié)點

3.render樹變化,比如減少了padding

4.窗口resize

5.最復(fù)雜的一種:獲取某些屬性轿腺,引發(fā)回流两嘴,
很多瀏覽器會對回流做優(yōu)化,會等到數(shù)量足夠時做一次批處理回流族壳,
但是除了render樹的直接變化憔辫,當(dāng)獲取一些屬性時,瀏覽器為了獲得正確的值也會觸發(fā)回流仿荆,這樣使得瀏覽器優(yōu)化無效贰您,包括
(1) offset(Top/Left/Width/Height)
(2) scroll(Top/Left/Width/Height)
(3) cilent(Top/Left/Width/Height)
(4) width,height
(5) 調(diào)用了getComputedStyle()或者IE的currentStyle
回流一定伴隨著重繪坏平,重繪卻可以單獨出現(xiàn)

所以一般會有一些優(yōu)化方案,如:

  • 減少逐項更改樣式锦亦,最好一次性更改style舶替,或者將樣式定義為class并一次性更新

  • 避免循環(huán)操作dom,創(chuàng)建一個documentFragment或div孽亲,在它上面應(yīng)用所有DOM操作坎穿,最后再把它添加到window.document

  • 避免多次讀取offset等屬性。無法避免則將它們緩存到變量

  • 將復(fù)雜的元素絕對定位或固定定位返劲,使得它脫離文檔流,否則回流代價會很高
    注意:改變字體大小會引發(fā)回流
    再來看一個示例:

var s = document.body.style;

s.padding = "2px"; // 回流+重繪
s.border = "1px solid red"; // 再一次 回流+重繪
s.color = "blue"; // 再一次重繪
s.backgroundColor = "#ccc"; // 再一次 重繪
s.fontSize = "14px"; // 再一次 回流+重繪
// 添加node栖茉,再一次 回流+重繪
document.body.appendChild(document.createTextNode('abc!'));

普通圖層和復(fù)合圖層

渲染步驟中就提到了composite概念篮绿。

可以簡單的這樣理解,瀏覽器渲染的圖層一般包含兩大類:普通圖層以及復(fù)合圖層

首先吕漂,普通文檔流內(nèi)可以理解為一個復(fù)合圖層(這里稱為默認復(fù)合層亲配,里面不管添加多少元素,其實都是在同一個復(fù)合圖層中)

其次惶凝,absolute布局(fixed也一樣)吼虎,雖然可以脫離普通文檔流,但它仍然屬于默認復(fù)合層苍鲜。

然后思灰,可以通過硬件加速的方式,聲明一個新的復(fù)合圖層混滔,它會單獨分配資源
(當(dāng)然也會脫離普通文檔流洒疚,這樣一來,不管這個復(fù)合圖層中怎么變化坯屿,也不會影響默認復(fù)合層里的回流重繪)

可以簡單理解下:GPU中油湖,各個復(fù)合圖層是單獨繪制的,所以互不影響领跛,這也是為什么某些場景硬件加速效果一級棒乏德。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吠昭,隨后出現(xiàn)的幾起案子喊括,更是在濱河造成了極大的恐慌,老刑警劉巖怎诫,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瘾晃,死亡現(xiàn)場離奇詭異,居然都是意外死亡幻妓,警方通過查閱死者的電腦和手機蹦误,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門劫拢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人强胰,你說我怎么就攤上這事舱沧。” “怎么了偶洋?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵熟吏,是天一觀的道長。 經(jīng)常有香客問我玄窝,道長牵寺,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任恩脂,我火速辦了婚禮帽氓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘俩块。我一直安慰自己黎休,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布玉凯。 她就那樣靜靜地躺著势腮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪漫仆。 梳的紋絲不亂的頭發(fā)上捎拯,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天,我揣著相機與錄音歹啼,去河邊找鬼玄渗。 笑死,一個胖子當(dāng)著我的面吹牛狸眼,可吹牛的內(nèi)容都是我干的藤树。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拓萌,長吁一口氣:“原來是場噩夢啊……” “哼岁钓!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起微王,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤屡限,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后炕倘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钧大,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年罩旋,在試婚紗的時候發(fā)現(xiàn)自己被綠了啊央。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片眶诈。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖瓜饥,靈堂內(nèi)的尸體忽然破棺而出逝撬,到底是詐尸還是另有隱情,我是刑警寧澤乓土,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布宪潮,位于F島的核電站,受9級特大地震影響趣苏,放射性物質(zhì)發(fā)生泄漏狡相。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一食磕、第九天 我趴在偏房一處隱蔽的房頂上張望谣光。 院中可真熱鬧,春花似錦芬为、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至日戈,卻和暖如春询张,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背浙炼。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工份氧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人弯屈。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓蜗帜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親资厉。 傳聞我的和親對象是個殘疾皇子厅缺,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容