瀏覽器工作原理(五):CSS解析(CSS parsing)
阿新 • • 發佈:2018-12-26
還記得簡介中提到的解析的概念嗎,不同於html,css屬於上下文無關文法,可以用前面所描述的解析器來解析。Css規範定義了css的詞法及語法文法。
看一些例子:
每個符號都由正則表示式定義了詞法文法(詞彙表):
comment///*[^*]*/*+([^/*][^*]*/*+)*//
num[0-9]+|[0-9]*"."[0-9]+
nonascii[/200-/377]
nmstart[_a-z]|{nonascii}|{escape}
nmchar[_a-z0-9-]|{nonascii}|{escape}
name{nmchar}+
ident{nmstart}{nmchar}*
“ident”是識別器的縮寫,相當於一個class名,“name”是一個元素id(用“#”引用)。
語法用BNF進行描述:
這說明,一個規則集合具有一個或是可選個數的多個選擇器,這些選擇器以逗號和空格(S表示空格)進行分隔。每個規則集合包含大括號及大括號中的一條或多條以分號隔開的宣告。宣告和選擇器在後面進行定義。ruleset : selector [ ',' S* selector ]* '{' S* declaration [ ';' S* declaration ]* '}' S* ; selector : simple_selector [ combinator selector | S+ [ combinator selector ] ] ; simple_selector : element_name [ HASH | class | attrib | pseudo ]* | [ HASH | class | attrib | pseudo ]+ ; class : '.' IDENT ; element_name : IDENT | '*' ; attrib : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S* [ IDENT | STRING ] S* ] ']' ; pseudo : ':' [ IDENT | FUNCTION S* [IDENT S*] ')' ] ; 說明:一個規則集合有這樣的結構 div.error , a.error { color:red; font-weight:bold; } div.error和a.error時選擇器,大括號中的內容包含了這條規則集合中的規則,這個結構在下面的定義中正式的定義了: ruleset : selector [ ',' S* selector ]* '{' S* declaration [ ';' S* declaration ]* '}' S* ;
Webkit CSS解析器(Webkit CSS parser)
Webkit使用Flex和Bison解析生成器從CSS語法檔案中自動生成解析器。回憶一下解析器的介紹,Bison建立一個自底向上的解析器,Firefox使用自頂向下解析器。它們都是將每個css檔案解析為樣式表物件,每個物件包含css規則,css規則物件包含選擇器和宣告物件,以及其他一些符合css語法的物件。圖12:解析css
處理指令碼及樣式表的順序
指令碼
web的模式是同步的,開發者希望解析到一個script標籤時立即解析執行指令碼,並阻塞文件的解析直到指令碼執行完。如果指令碼是外引的,則網路必須先請求到這個資源——這個過程也是同步的,會阻塞文件的解析直到資源被請求到。這個模式保持了很多年,並且在html4及html5中都特別指定了。開發者可以將指令碼標識為defer,以使其不阻塞文件解析,並在文件解析結束後執行。Html5增加了標記指令碼為非同步的選項,以使指令碼的解析執行使用另一個執行緒。web的模式是同步的,開發者希望解析到一個script標籤時立即解析執行指令碼,並阻塞文件的解析直到指令碼執行完。如果指令碼是外引的,則網路必須先請求到這個資源——這個過程也是同步的,會阻塞文件的解析直到資源被請求到。這個模式保持了很多年,並且在html4及html5中都特別指定了。開發者可以將指令碼標識為defer,以使其不阻塞文件解析,並在文件解析結束後執行。Html5增加了標記指令碼為非同步asyn的選項,以使指令碼的解析執行使用另一個執行緒。
預解析
Webkit和Firefox都做了這個優化,當執行指令碼時,另一個執行緒解析剩下的文件,並載入後面需要通過網路載入的資源。這種方式可以使資源並行載入從而使整體速度更快。需要注意的是,預解析並不改變Dom樹,它將這個工作留給主解析過程,自己只解析外部資源的引用,比如外部指令碼、樣式表及圖片。樣式表(Style sheets)
樣式表採用另一種不同的模式。理論上,既然樣式表不改變Dom樹,也就沒有必要停下文件的解析等待它們,然而,存在一個問題,指令碼可能在文件的解析過程中請求樣式資訊,如果樣式還沒有載入和解析,指令碼將得到錯誤的值,顯然這將會導致很多問題,這看起來是個邊緣情況,但確實很常見。Firefox在存在樣式表還在載入和解析時阻塞所有的指令碼,而Chrome只在當指令碼試圖訪問某些可能被未載入的樣式表所影響的特定的樣式屬性時才阻塞這些指令碼。------------------------------------下一節,渲染樹構建------------------------------------