關於瀏覽器的渲染過程

對於這個過程,我是真的看了好多資料都沒能達到很是透徹的理解,如下是我所能瞭解並理解的一些:特此整理並記錄下來,僅供本身的學習啦javascript

關於瀏覽器的一些基礎知識css

瀏覽器的主要功能是向服務器發出請求,在瀏覽器窗口中顯示咱們所選擇的的網絡資源,咱們所選擇的網絡資源通常是指html文檔,PDF,圖片或其餘類型的東西(動態文件之類的),資源的位置由用戶使用的URL(統一資源定位符)指定。html

瀏覽器解釋並解釋html文件的方式是在html和css規範中指定的,這些規範由W3C進行維護,可是這麼多年過去了,各大瀏覽器並無徹底聽從這些規範,同時還在開發本身獨有的擴展程序,這對前端開發人員來講就真的太苦逼了,這種兼容性問題實在頭疼,現在,大多數瀏覽器是或多或少的聽從W3C的規範。前端

用過各類瀏覽器的確定也注意到它們彼此之間是有不少相同的元素的,其中包括:html5

輸入欄(URL)java

前進和後退node

書籤設置linux

刷新按鈕和中止加載按鈕web

返回主界面的按鈕正則表達式

各瀏覽器也都還有着本身各自的功能,好比Firefox的下載管理器之類的。

瀏覽器的高層結構

 

1.用戶界面-包括地址欄,前進、後退按鈕書籤單等,除了瀏覽器主窗口的顯示的頁面外,其餘顯示的各個部分都屬於用戶界面。

2瀏覽器引擎-在用戶界面和呈現引擎之間傳送指令。

3呈現引擎-負責顯示請求的內容。若是請求的內容是html,它就解析html和css內容,並將解析後的內容顯示在屏幕上。

4.網絡-用於網絡調用,好比http請求。這個接口與平臺無關,併爲全部平臺提供底層實現。

5.用戶界面後端-用於繪製基本的窗口小部件,好比組合框和窗口,其公開了與平臺無關的通用接口,而在底層使用操做系統的用戶界面方法

6.Javascript解析器,用於解析和執行javascript代碼。

7.數據存儲,也就是咱們的瀏覽器的存儲,像cookie啦,localstroage啦,sessionstorage(講到這我又想回顧一下這三個東西的區別了,先說一下,這三個都是存儲在瀏覽器端的,主要是存儲的大小不一樣,數據有效期不一樣,仍是改天再另外擼一篇吧!)h5定義了‘網絡數據庫’,這是一個完整可是輕便的瀏覽器內存數據庫。

值得注意的是,和大多數瀏覽器不一樣,Chrome瀏覽器的每一個標籤頁都對應一個呈現引擎實例。每一個標籤頁都是一個獨立的進程(那麼這個就是它完虐各大瀏覽器的緣由之一???,我猜的)

呈現引擎

呈現引擎的做用很明顯就是呈現咯,也就是在瀏覽器的屏幕上顯示請求的內容。

默認狀況下,呈現引擎可顯示html和XML文檔與圖片。經過插件(瀏覽器的擴展程序),還能夠顯示其餘類型的內容;使用PDF查看器插件就能顯示PDF文檔。可是他的主要用途是:顯示使用css格式化的html內容和圖片。

那麼呈現引擎也有好幾種,Firefox使用的是Gecko,這是mozilla公司本身開發的呈現引擎,Chrome和safair都是webkit。

webkit是一種開放源代碼的呈現引擎,起初用於linux平臺,隨後由apple公司修改,從而它是支持蘋果機和windows的。

接下來看主流程

接下來重點來啦:

呈現引擎將開始解析html文檔,並將各標記逐個轉化成內容樹上的DOM節點。同時會解析外部css文件以及樣式元素中的樣式數據。html中這些帶有視覺指令的樣式信息將用於建立另外一個樹結構,我叫它渲染樹,也有人叫它呈現樹。

渲染樹包含多個視覺屬性的矩形,這些矩形的排列順序就是他們將在屏幕上顯示的順序。

渲染樹構建完畢後,進入佈局處理階段,也就是爲每一個節點分配一個應出如今屏幕上的確切座標,下一個階段是繪製--這時呈現引擎會遍歷渲染樹,由用戶界面後端將每一個節點繪製出來。

須要着重指出的是,這是一個漸進的過程,爲了達到更好的用戶體驗,呈現引擎會力求儘快將內容顯示在屏幕上,它沒必要等到整個html文檔解析完畢,就會開始構建渲染樹和設置佈局,在不斷的接收和處理來自網絡的其他內容的同時,呈現引擎將會部份內容解析並呈現出來。

雖然二者的術語不一樣,但總體流程是基本相同的。

Gecko將視覺格式化元素組成的樹稱爲框架樹。每一個元素都是一個框架。webkit則是呈現樹,它由呈現對象組成,對於元素的位置,webkit使用的術語是佈局,而Gecko稱之爲重排。對於鏈接DOM節點和可視化信息從而建立呈現樹的過程,webkit稱爲附加,有一個細微的非語義化差異,就是Gecko和html與DOM樹之間還有一個稱爲內容槽的層,用於生成DOM元素。

接下來逐一論述流程中的每個部分:

解析-綜述

解析是呈現引擎中很是重要的一個環節,所以咱們要更深刻地理解。首先,先來介紹一下解析。

解析文檔是指將文檔轉化成爲有意義的結構,也就是可以讓代碼理解和使用的結構。解析獲得的結果一般是表明了文檔結構的節點數,它稱爲解析樹或者語法樹。

講了這麼久的樹,那麼什麼是樹,來看:

 語法:解析是以文檔所聽從的語法規則(編寫文檔所用的語言或格式)爲基礎的,全部能夠解析的格式都必須對應肯定的語法(由詞彙和語法規則構成)。這稱爲與上下文無關的語法。人類語言並不屬於這樣的語言,所以沒法用常規的解析技術進行解析。

(以上這段,我目前都還不是很懂,之後回來看看吧)

解析器和詞法分析器的組合

解析的過程能夠分爲兩個子過程:詞法分析和語法分析。

詞法分析是將輸入內容分割成大量標記的過程。標記是語言中的詞彙,即構成內容的單位,在人類語言中,它至關於語言字典中的單詞。

語法分析是應用語言的語法規則的過程

解析器一般將解析工做分給兩個組件來處理:詞法分析器(有時候也叫標記生成器),負責將輸入內容分解成一個個有效的標記;而解析器負責根據語言的語法規則來分析文檔結構,從而構建解析樹。詞法分析器知道如何將無關的字符(好比空格和換行符)分離出來。

解析是一個迭代的過程。一般,解析器會向詞法分析器請求一個新標記,並嘗試將其與某條語法規則進行匹配。若是發現了匹配規則,則解析器會將一個對應於標記的節點添加到解析樹中,而後繼續請求下一個標記。

若是沒有規則可匹配,解析器就會將標記存儲到內部,並繼續請求標記,直至找到可與全部內部存儲的標記匹配的規則。若是找不到任何匹配規則,解析器就會引起一個異常。這意味着文檔無效,包含語法錯誤。

翻譯:

不少時候,解析樹不是最終產品。解析一般是在翻譯過程當中使用的,而翻譯是指將輸入文檔轉換成另外一種格式。編譯就是這樣一個例子。編譯器可將源代碼編譯成機器代碼,具體過程是首先將源代碼解析成解析樹,而後將解析樹翻譯成機器代碼文檔。

解析示例:

以前已經看了經過數學表達式簡歷瞭解析樹。如今,讓咱們試着定義一個簡單的數學語言,用來演示解析的過程。

1:構成語言的語法單位是表達式,項和運算符。

2.咱們用的語言能夠包含任意數量的表達式。

3.表達式的定義是:一個項接一個運算符,而後再接一個項。

4.運算符是加號或減號。

5.項是一個整數或一個表達式。

好了,能夠分析 2+3—1了

匹配語法規則的第一個子串是2,而根據第五條詞法規則,這是一個項。匹配語法規則的第二個子串是2+3,而根據第三條規則,這是一個表達式。下一個匹配項已經到了輸入的結束。2+3-1是一個表達式,由於咱們已經知道2+3是一個項,這樣就符合第三條條規則。2++不與任何規則匹配,所以是無效的輸入。

好像有點兒懂了

解析器類型

有兩種基本類型的解析器:自上而下解析器和自下而上解析器。直觀來講,自上而下的解析器從語法的高層結構出發,嘗試從中找到匹配的結構。而自下而上的解析器從底層規則出發,將輸入內容轉化爲語法規則,直至知足高層規則。

接下來能夠看看這兩種解析器會如何解析咱們的示例:

自上而下的解析器會從高層開始:首先將2+3標識爲一個表達式,而後將2+3-1標識爲一個表達式(標識表達式的過程涉及到匹配其餘規則,可是起點是最高級別的規則,懂)

自下而上的解析器將掃描輸入內容,找到匹配的規則後,將匹配的輸入內容替換成規則。如此繼續替換,直至輸入內容的結尾。部分匹配的表達式保存在解析器的堆棧中。

這種自下而上的解析器稱爲移位歸約解析器,由於輸入在向右移位(設想有一個指針從輸入內容的開頭移動到結尾),而且逐漸歸約到語法規則上。

不懂

 自動生成解析器

有一些工具是能夠幫助生成解析器的,它們稱爲解析器生成器。咱們只要提供咱們所用的語法(語法規則和詞彙),它就會生成相應的解析器。建立解析器須要對解析器有深入的理解,而人工建立優化的解析器並非一件容易的事情,因此解析器生成器是很是實用的。

webkit實用了兩種很是有名的解析器生成器:用於建立詞法分析器的flex以及用於建立解析器的bison。flex的輸入是包含標記的正則表達式定義的文件,bison的輸入是採用BNF格式的語言語法規則。

HTML解析器

html解析器的任務是將html標記解析成解析樹。

html語法定義

html的詞彙和語法在W3C組織建立的規範中進行了定義。當前的版本是html5.

非與上下文無關的語法

正如咱們在解析過程的簡介中已經瞭解到,語法能夠用BNF等格式進行正式定義。

很遺憾,全部的常規解析器都不適用於HTML(啊,我才知道)。html並不能很容易地用解析器所需的與上下文無關的語法來定義。有一種能夠定義html的正規格式:DTD(document type definition),但它不是與上下文無關額語法。

這起初看起來很奇怪:html與XML很是類似。有不少XML解析器可使用。html存在一個XML變體(XHTML),那麼有什麼大的區別呢,區別在於html的處理更爲「寬容」,它容許你省略某些隱式添加的標記,有時候還能省略一些起始或結束的標記等,和XML嚴格的語法不一樣,html總體來看是一種「軟性」的語法。

顯然,這種看上去細微的差異實際上卻帶來了巨大的影響。一方面,這是HTML如此流行的緣由:它能包容咱們的錯誤;簡化網絡開發。另外一方面,這使得它很難編寫正式的語法。歸納的說,html沒法很容易地經過常規解析器解析(由於它的語法不是與上下文無關的語法),所以也沒法經過XML解析器來解析。

 

HTML DTD

html的定義採用了DTD格式,這個格式可用於定義SGML族的語言。(什麼鬼)。它包含了全部容許使用的元素及其屬性和層次結構的定義。如上文所述,HTML DTD沒法構成與上下文無關的語法。

DTD存在一些變體。嚴格模式徹底遵循html規範,而其餘模式可支持之前的瀏覽器多使用的標記。這樣作的目的是確保向下兼容一些舊版本的內容。最新的嚴格模式DTD在這http://www.w3.org/TR/html4/strict.dtd 

 

DOM

解析器的輸出「解析樹」是由DOM元素和屬性節點構成的樹結構。DOM是文檔對象模型的縮寫,它事HTML文檔的對象表示,同時也是外部內容(css js)與html元素之間的接口。

解析算法

HTML沒法用常規的自上而下或自下而上的解析器進行解析。緣由在於:

1.語言的寬容本質。

2.瀏覽器從來對一些常見的無效html用法採起包容的態度。

3.解析過程須要不斷地反覆。源內容在解析過程當中一般不會改變,可是在HTML中,腳部標記若是包含document.write,就會添加額外的標記,這樣解析過程實際上就更改了輸入內容。

因爲不能使用常規的解析過程,瀏覽器就建立了自定義的解析器來解析HTML。http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html,這個地址是html5規範詳細德描述瞭解析算法。此算法由兩個階段組成:標記化和樹構建。

標記化是詞法分析過程,將輸入內容解析成多個標記。HTML標記包括起始標記,結束標記,屬性名和屬性值。標記生成器識別標記,傳遞給樹構造器,而後接受下一個字符以識別下一個標記;如此反覆知道輸入結束。

標記化算法

該算法的輸出結果是html標記。該算法使用狀態機來表示。每個狀態接收來自輸入信息流的一個或多個字符,並根據這些字符更新下一個狀態。當前標記化狀態和樹結構狀態會影響下一個狀態的決定。這意味着,即使接收的字符相同,對於下一個正確的狀態也會產生不一樣的結果,具體取決於當前的狀態。該算法至關複雜,沒法詳述,因此咱們經過一個簡單的示例來理解。

將下面的html代碼標記化:

<html>

<body>

hello xiaoai

</body>

</html>

初始化時數據狀態。遇到字符<時,狀態更改成「標記打開狀態」。接收一個a-z字符會建立「起始標記」,狀態更改成「標記名稱狀態」。這個狀態會一直保持到接收>。在此期間接收的每一個字符都會附加到新的標記名稱上。

遇到>標記時,會發送當前的標記,狀態改回「數據狀態」。<body>標記也會進行一樣的處理。目前html和body標記均已發出。如今咱們回到「數據狀態」。接收到hello xiaoai 中的h字符時,將建立併發送字符標記,直到接收</body>中的<。咱們將爲hello xiaoai 中的每個字符都發送一個字符標記。(不錯,講得好詳細,<攤手>)

如今回到「標記打開狀態」。接收下一個輸入字符/時,會建立 end tag token 並改成「標記名稱狀態」。咱們會再次保持這個狀態,直到回收>.而後將發送新的標記,並回到「數據狀態」。</html>輸入也會一樣的處理。

 

樹構建算法

    在建立解析器的同時,也會建立document對象。在樹構建階段,以document爲根節點的DOM樹也會不斷進行修改,向其中添加各類元素,標記生成器發送的每一個節點都會由樹構建器進行處理。規範中定義了每一個標記所對應的dom元素。這些元素會在接收到相應的標記時建立。這些元素不只會添加到dom樹中,還會添加到開放元素的堆棧中。此堆棧用於糾正嵌套錯誤和處理未關閉的標記。其算法也能夠用狀態機來描述。這些狀態稱爲「插入模式」。

仍是上面的代碼,來看看樹構建過程。

<html>

<body>

hello xiaoai

</body>

</html>

樹構建階段的輸入是一個來自標記化階段的標記序列。第一個模式是「initial mode」。接收html標記後轉爲「before html」模式,並在這個模式下從新處理此標記。這樣會建立一個htmlelement元素,並將它附加到document的根對象上。

而後狀態改成「before head」。此時咱們接收「body」標記。即便咱們的示例中沒有「head」標記,系統也會隱式建立一個html headelement,並將它附加的樹中。

如今進入了「 in head」模式,而後轉入「after head」模式。系統對body 標記進行從新處理,建立並插入HTML bodyelement ,同時模式轉變爲「body」

如今,接收由「hello xiaoai」字符串生成的一系列字符標記。接收第一個字符時會建立並插入「Text」節點,而其餘字符也將附加到該節點。

接收body結束標記會觸發「after body」模式。如今咱們將接收html結束標記,而後進入「after after body」模式。接收到文件結束標記後,解析就此結束。

解析結束後

   在此階段,瀏覽器會將文檔標註爲交互狀態,並開始解析那些處於「deferred」模式的腳本,也就是那些應在文檔解析完成後才執行的腳本。而後,文檔狀態設置爲「完成」,一個「加載」事件將隨之觸發,連接:http://www.w3.org/TR/html5/syntax.html#html-parser

瀏覽器的容錯機制

咱們在瀏覽html網頁時歷來不會看到「語法無效」的錯誤,這是由於瀏覽器會糾正任何無效內容,而後繼續工做。

HTML5 規範了一部分這樣的要求,webkit在html解析器類的開頭註釋對此做了很好的歸納:

瀏覽器對標記化輸入內容進行解析,以構建文檔樹。若是文檔的格式正確,就直接進行解析。

遺憾的是,咱們不得不處理不少格式錯誤的html文檔,因此解析器必須具有必定的容錯性。

咱們至少可以處理如下的錯誤狀況:

1明顯不能在某些外部標記中添加的元素。此狀況下,咱們應該關閉全部的標記,直到出現禁止添加的元素,而後再加入該元素。

2.咱們不能直接添加的元素。這極可能是網頁做者忘記添加了其中的一些標記(或者其中的標記是可選的)。這些標籤可能包括:HTML head body tbody tr td li。

3.向inline元素內添加block 元素。關閉全部inline元素,直到出現下一個較高級的block元素。

4.若是這樣仍然無效,可關閉全部元素,直到能夠添加元素爲止,或者忽略該標記。

以上這麼多都在講html的解析,接下來看看css的解析

css 解析

和html不一樣,css是上下文無關的語法,可使用各類解析器進行解析。事實上,css規範定義了css的詞法和語法。連接:http://www.w3.org/TR/CSS2/grammar.html

webkit css解析器

webkit使用flex和bison解析器生成器,經過css語法文件自動建立解析器。正如咱們以前在解析器的介紹中所說,bison會建立自下而上的移位規約解析器。Firefox使用的是人工編寫的自上而下的解析器。這兩種解析器會將css文件解析成stylesheet對象,且每一個對象都包含css規則。css規則包含選擇器和聲明對象,以及其餘與css語法對應的對象。

不太懂

接下來腳本!

處理腳本和樣式表的順序

腳本

     網絡的模型是同步的,網頁做者但願解析器遇到<script>標記時當即解析並執行腳本,文檔的解析將中止,直到腳本執行完畢。若是腳本是外部的,那麼解析過程會中止,直到從網絡同步抓取資源完成後再繼續。此模型已經用了不少年了,也在HTML4和html5規範中進行了指定。做者也能夠將腳本標註爲「defer」,這樣它就不會中止解析文檔,而是等到解析結束後才執行。h5增長了一個選項,可將腳本標記爲異步,以便其餘線程解析和執行。

預解析

   webkit和Firefox都進行了這項優化。在執行腳本時,其餘線程會解析文檔的其他部分,找出並加載須要經過網絡加載的其餘資源。經過這種方式,資源能夠在並行鏈接上加載,從而提升整體速度,可是,預解析器不會修改DOM樹,而是將這項工做交由主解析器處理;預解析器只會解析外部資源(js,css,圖片)的引用。

樣式表

    另外一方面,樣式表有着不一樣的模型。理論上來講,應用樣式表不會更改dom樹,所以彷佛沒有必要等待樣式表並中止解析。但這涉及到一個問題,就是腳本在文檔解析階段會請求樣式信息,若是當時尚未加載和解析樣式,腳本就會得到錯誤的回覆,這樣顯然會產生不少問題。這看上去是一個非典型案例,可是事實上很是廣泛。Firefox在樣式表加載和解析的過程當中,會禁止全部的腳本。而對於webkit而言,僅當腳本嘗試訪問樣式屬性可能受還沒有加載的樣式表影響時,它纔會禁止該腳本。

 

呈現樹的構建

     在DOM樹構建的同時,瀏覽器還會構建另外一個樹結構:呈現樹。這是可視化元素按照其顯示順序而組成的樹,也是文檔的可視化表示。它的做用是按照正確順序繪製內容。

Firefox 將呈現樹中的元素稱爲「框架」。webkit使用的術語是呈現器或呈現對象。

呈現器知道如何佈局並將自身及其子元素繪製出來。

webkit的呈現對象類是全部呈現器的基類。

class RenderObject{
   virtual void layout();
   virtual void paint(PaintInfo);
   virtual void rect repaintRect();
   Node* node;  //the DOM node
   RenderStyle* style;  // the computed style
   RenderLayer* containgLayer; //the containing z-index layer
}
每個呈現器都表明了一個矩形的區域,一般對應於相關的css框,這一點在css2中有描述,它包含寬度,高度和位置等幾何信息。
框的類型會受到與節點相關的「display」樣式屬性的影響。元素類型也是考慮因素之一,例如表單控件和表格都對應特殊的框架。若是一個元素須要建立特殊的呈現器,就會替換createRender方法,在webkit中,呈現器所指向的樣式包含了一些和幾何無關的信息。
呈現樹和DOM樹的區別
 
    呈現器是和DOM元素相對應的,但不是一一對應。非可視化的dom元素不會插入到呈現樹中,例如「head」元素。若是元素的display屬性值爲none,那麼也不會出如今呈現樹中(可是visibility屬性值爲hidden的元素是會顯示在呈現樹中的)
有一些DOM元素對應多個可視化對象,他們每每是具備複雜結構的元素,沒法用單一的矩形來描述。例如「select」元素有三個呈現器:一個用於顯示區域,一個用於下拉列表框,還有一個用於按鈕。若是寬度不夠,文本沒法在一行中顯示而分爲多行,那麼新的行也會做爲新的呈現器而添加。
另外一個關於多呈現器的例子是格式無效的HTML。根據css規範,inline元素只能包含block元素或inline元素中的一種。若是出現了混合內容,則應建立匿名的block呈現器,以包裹inline元素。
有一些呈現對象對應於dom節點,但在樹中所在的位置與dom節點不一樣。浮動定位和絕對定位元素就是這樣,他們處於正常流以外,放置在樹中的其餘地方,並映射到真正的框架,而放在原位的是佔位框架。
 
構建呈現樹的流程
 
      在Firefox中,系統會針對DOM更新註冊展現層,做爲偵聽器。展現層將框架建立工做委託給frameconstructor,由該構造器解析樣式並建立框架。
      在webkit中,解析樣式和建立呈現器的過程叫「附加」。每一個dom節點都有一個「attach」方法。附加是同步進行的,將節點插到dom樹須要調用新的節點「attach」方法。
      處理HTML和body標記就會構建呈現樹根節點。這個根節點呈現對象對應於css規範中所說的容器block,這是最上層的block,包含了其餘全部的block。它的尺寸就是視口,即瀏覽器窗口顯示區域的尺寸。Firefox稱之爲viewportframe,而webkit稱之爲renderview。這就是文檔所指向的呈現對象。呈現樹的其他部分以dom樹節點插入形式來構建。
 
 
樣式計算
   
      構建呈現樹時,須要計算每個呈現對象的可視化屬性。這是經過計算每一個元素的樣式屬性來完成的。樣式包括來自各類來源的樣式表,inline樣式元素和html中的可視化屬性(bgcolor)。其中後者將通過轉化以匹配css樣式屬性。
 
       樣式表的來源包括瀏覽器的默認樣式表,由網頁做者提供的樣式表以及由瀏覽器用戶提供的用戶樣式表(瀏覽器容許你本身定義喜歡的樣式,Firefox中,用戶能夠將本身喜歡的樣式表放在「Firefox profile」文件夾下)
 
   樣式計算存在如下難點:
1.樣式數據是一個超大的結構,存儲了無數的樣式屬性,這可能形成內存問題。
2.若是不進行優化,爲每一元素查找匹配的規則會形成性能問題。要爲每個元素遍歷整個規則表來尋找匹配規則,這是一項浩大的工程。選擇器會具備很複雜的結構,這就會致使某個匹配過程一開始看起來極可能是正確的,但最終發現實際上是徒勞的,必須嘗試其餘匹配路徑。
好比 :如下這個組合選擇器:
div div div div{。。。}
這意味着 規則使用於三個div元素的子代div。若是你要檢查規則是否適用於某個指定的div元素,應選擇樹上一條向上路徑進行查詢。你要向上遍歷節點樹,結果發現只有兩個div,並且規則不適用。而後你必須嘗試樹中其餘的路徑。
3.應用規則涉及至關複雜的層疊規則(用於定義這些規則的層次)
看看瀏覽器是怎麼處理這些問題
共享樣式數據
 
webkit 節點會引用樣式對象(renderstyle)。這些對象在某個狀況能夠由不一樣節點共享。這些節點是同級關係,而且:
1.這些元素必須處於相同的鼠標狀態(例如,不容許其中一個是:hover,而另外一個不是)
2.任何元素都沒有ID
3.標記名稱應匹配
4類屬性應匹配
5.映射屬性的集合必須徹底相同的
6.連接狀態必須匹配
7.焦點狀態必須匹配
8.任何元素必須匹配
9元素中不能有任何inline樣式屬性
10.不能使用任何同級選擇器。
 
是否是很難懂?<攤手>
直接看佈局吧
 
佈局
   呈現樹在建立完成並添加到呈現樹時,並不包含位置和大小信息。計算這些值得過程稱爲佈局或重排。
  HTML採用基於流的佈局模式,這意味着大多數狀況下只要一次遍歷就能計算出幾何信息。處於流中靠後位置元素一般不會影響靠前元素的幾何特徵,所以佈局能夠按從左到右,從上至下遍歷文檔。可是也有例外狀況,好比HTML表格的計算就須要不止一次的遍歷。
   座標系是相對於根框架而創建的,使用的是上左標和左座標。
佈局是一個遞歸的過程,它從根呈現器(<html>)開始,而後遞歸遍歷部分或全部的框架層次結構,爲每個須要計算的呈現器計算幾何信息。
全部的呈現器都有一個「layout」或者「reflow」方法,每個呈現器都會調用其須要進行佈局的子代的layout方法。
 
 
定位方案
1.普通:根據對象在文檔中的位置進行定位,也就是說對象在呈現樹中的位置和它在dom樹中的位置類似,並根據其框架類型和尺寸進行佈局。
2.浮動:對象先按照普通流進行佈局,而後儘量地項右或向左移動。
3.絕對:對象在呈現樹中的位置和它在dom樹中的位置不一樣。
定位方案有position屬性和float屬性設置的。
若是值時static和relative,就是普通流。
若是值時absolute和fixed,就是絕對定位。
static定位無需定義位置,而是使用默認定位。對於其餘方案,網頁做者須要指定位置:top,bottom,left,right。
框的佈局方式是由如下因素決定的:
框類型
框尺寸
定位方案
外部信息,例如圖片大小和屏幕大小
 
 
框類型:
block框:造成一個block,在瀏覽器窗口擁有其本身的矩形區域。
inlinne框:沒有本身的block,可是位於容器block內。
block採用的是一個接一個的垂直格式,而inline採用的是水平格式。
inline框放置在行中或行框中,這些行至少和最高的框同樣高,還能夠更高,當框根據「底線」對齊時,這意味着元素的底部須要根據其餘框中非底部的位置對齊。若是容器寬度不夠,inline元素會分爲多行放置,在段落中常常發生這種狀況。
 
 
 
分層展現
z-index css屬性指定的。它表明了框的第三個維度,也就是沿z軸方向的位置。
 
看到這已經頭暈暈了,但還得往下:
 
 
看看如何簡易的描述瀏覽器的渲染過程
 
1.瀏覽器會將HTML解析成一個dom樹,dom樹的構建過程是一個深度遍歷過程:當前節點的全部子節點都構建好後纔會去構建當前節點的下一個兄弟節點。
2.將css解析成css規則樹。
3.根據DOM樹和css規則樹來構造rendering樹(渲染樹或呈現樹)rendering樹並不等於DOM樹,前面講過啦。
4.有了渲染樹,瀏覽器已經能知道網頁中有哪些節點,各個節點的css定義以及它們的從屬關係,下一步操做稱之爲「layout」,就是計算出每一個節點在屏幕中的位置
5.在下一步就是繪製,即遍歷rendering樹,並使用UI後端繪製每一個節點。
上述這個過程是逐步完成的,爲了更好的用戶體驗,渲染引擎會盡量早的將內容呈現到屏幕上,並不會等到全部html都解析完成後再去構建和佈局rendering樹,它是解析完一部份內容就顯示一部份內容,同時,可能還在經過網絡下載其餘內容。
 
 總的來講:瀏覽器的加載,解析,渲染過程,我概括以下
1。輸入網址
2.瀏覽器查找域名的IP地址
3.瀏覽器給web服務器發送一個http請求
4.  網站服務的永久重定向響應(?)
5.瀏覽器跟蹤重定向地址。
如今瀏覽器知道了要訪問的正確地址,因此它會發送另外一個獲取請求
6.服務器處理請求,服務器接收到獲取請求,而後返回一個響應。
7.服務器返回一個html響應
8.瀏覽器開始顯示html(這裏就會發生上面的解析啦,渲染啦等過程)
9.瀏覽器發送請求,以獲取嵌入在html中的對象,就是再次發送http請求以獲取js,css,圖片等資源(這個過程會再次發生dns域名查詢,發送請求,重定向等等這些步驟)
 
 
渲染引擎在取得內容後:
解析html以構建DOM樹-->構建渲染樹rendering樹-->佈局(重排)rendering樹-->繪製rendering樹
相關文章
相關標籤/搜索