css渲染原理
- 瀏覽器渲染原理
- 瀏覽器接收到服務(wù)器返回的html頁面害驹。
- 瀏覽器開始構(gòu)建DOM樹(DOM TREE),遇到css樣式會構(gòu)建CSS規(guī)則樹(css RULE TREE)。
- 遇到j(luò)avascript會通過DOM API和CSSDOM API來操作DOM Tree和CSS Rule Tree。
- 解析完成后,瀏覽器會通過DOM Tree和CSS Rule Tree來構(gòu)造Rendering Tree(渲染樹)萎胰。
- 最后,渲染樹構(gòu)建完成后就是“布局”處理棚辽,也就是確定每個(gè)節(jié)點(diǎn)在屏幕上的確切顯示位置技竟。
- 渲染之后,開始“繪制”屈藐,遍歷渲染樹榔组,并用UI后斷層,將每一個(gè)節(jié)點(diǎn)繪制出來联逻。
- css渲染規(guī)則
- css的渲染規(guī)則搓扯,是從上到下,從右到左渲染的包归。
.main h4 a {font-size: 14px}
- 渲染過程是這樣的:首先先找到所有的a锨推,沿著a的父元素查找h4,然后再沿著h4公壤,查找.main换可。中途找到了符合匹配規(guī)則的節(jié)點(diǎn)就加入結(jié)果集。如果找到根元素的html都沒有匹配境钟,則這條路徑不再遍歷锦担。下一個(gè)a開始重復(fù)這個(gè)查找匹配俭识,直到?jīng)]有a繼續(xù)查找慨削。
-瀏覽器的這種查找規(guī)則就是為了盡早過濾掉一些無關(guān)的樣式規(guī)則和元素。 - 頁面渲染與執(zhí)行過程
- 通過一個(gè)例子套媚,我們來詳細(xì)看看頁面渲染和執(zhí)行過程到底是怎么工作的:
<html>
<body>
<link href="example.css" rel="stylesheet">
<div>Hi here</div>
<script>
document.write('<script src="other.js"><scr' + 'ipt>')
</script>
<div>Hi again</div>
<script src="last.js"></script>
</body>
</html>
- 解析器遇到了example.css缚态,并將它從網(wǎng)絡(luò)中下載下來。下載樣式表的過程是耗時(shí)的堤瘤,但是解析器并沒有被阻塞玫芦,繼續(xù)往下解析
- 解析器遇到<script>標(biāo)簽,但是由于樣式文件下載未完成本辐,阻塞了該腳本的執(zhí)行(上面已指出)桥帆。解析器(構(gòu)建DOM樹和 CSS規(guī)則樹)被阻塞住医增,不能繼續(xù)往下解析
- 因?yàn)殇秩緲涫荄OM樹 和 CSS規(guī)則樹 來構(gòu)造,所以此時(shí)老虫,渲染樹的構(gòu)建也被阻塞
- 渲染樹是繪制觸發(fā)條件之一叶骨,因此Hi there!也就 不能被繪制(painting->display)到頁面中。
- 繪制的觸發(fā)條是: 渲染樹構(gòu)建完成祈匙,并遇到了阻塞
- 接下來忽刽,一旦example.css下載完成,內(nèi)聯(lián)的腳本執(zhí)行完了之后夺欲,解析器開始執(zhí)行遇到的<script>標(biāo)簽跪帝,并查到src屬性中的other.js文件,立即被阻塞些阅,開始下載other.js伞剑;
- 因?yàn)榻馕銎鞅蛔枞|發(fā)了繪制條件扑眉,瀏覽器就會收到繪制的請求纸泄,“Hi,here”就會顯示在頁面上
- other.js加載完成了之后腰素,解析器繼續(xù)向下解析聘裁,遇到 last.js 之后又被阻塞,
- 因?yàn)榻馕銎髟俅伪蛔枞В中纬闪?“繪制” 條件衡便,因此繪制DOM樹的內(nèi)容,即洋访,“Hi镣陕,again”就會顯示在頁面上。
- last.js加載完成姻政,并且被執(zhí)行呆抑。
- css優(yōu)化
-
把 Stylesheets 放在 HTML 頁面頭部
- 瀏覽器在所有的 stylesheets 加載完成之后,才會開始渲染整個(gè)頁面汁展,在此之前鹊碍,瀏覽器不會渲染頁面里的任何內(nèi)容,頁面會一直呈現(xiàn)空白食绿。這也是為什么要把 stylesheet 放在頭部的原因侈咕。如果放在 HTML 頁面底部,頁面渲染就不僅僅是在等待 stylesheet 的加載器紧,還要等待 html 內(nèi)容加載完成耀销,這樣一來,用戶看到頁面的時(shí)間會更晚铲汪。
- 對于 @import 和 <link> 兩種加載外部 CSS 文件的方式:@import 就相當(dāng)于是把 <link> 標(biāo)簽放在頁面的底部熊尉,所以從優(yōu)化性能的角度看罐柳,應(yīng)該盡量避免使用 @import 命令
-
嵌套層級不要超過三級
- 一般情況下,嵌套層級不要超過三級狰住,過渡的嵌套會導(dǎo)致代碼變得臃腫硝清,導(dǎo)致css文件體積變大,造成性能上的浪費(fèi)转晰,影響渲染的速度芦拿;css層級太多,也過于依賴html DOM結(jié)構(gòu)查邢,不易于維護(hù)蔗崎。如果層級比較深,就直接定義一個(gè)class代替多余的層級扰藕。
css 命名規(guī)范缓苛,書寫規(guī)范。
-
多用繼承屬性
- 盡量的繼承父類樣式 邓深,重復(fù)的定義會造成很多不必要的性能浪費(fèi)未桥。
少用濾鏡,好用hack芥备,少用position: absolute;
使用簡寫樣式冬耿。見下例
.mg { margin-top: 20px; margin-right: 0px; margin-bottom: 20px; margin-left: 100px; }
-
可以簡寫為
.mg {
margin: 20px 0px 20px 100px;
}
7. 不要再id選擇器和class選擇器前使用標(biāo)簽名 例如:
div #box {
color: white;
}
-
id選擇器本身就能唯一確定一個(gè)元素,沒必要再在前面加上標(biāo)簽名萌壳。同樣亦镶,類選擇器也是,如果需要給某個(gè)標(biāo)簽的類增添額外的樣式袱瓮,建議使用另一個(gè)類名缤骨。這種情況下,也可以使用 div .box{} 形式尺借,差別不大绊起。
平鋪的背景圖片不要過小,1px的圖片平鋪長寬25px的區(qū)域塊燎斩,需要2500次虱歪,太影響渲染速度。
謹(jǐn)慎使用float瘫里,具體細(xì)節(jié)請參考我的另一片文章 《深入理解f浮動與清除浮動》
-
合理化布局(模塊化布局)
- 可以把樣式劃分為”基類“ 和 “擴(kuò)展類”实蔽; 把模塊基本相同的樣式寫在基類里荡碾,不同的再重新用class定義谨读,寫在擴(kuò)展類中。
盡量少用通配符坛吁,只用通配符設(shè)定一切基礎(chǔ)的樣式劳殖,如:
* {margin:0; padding:0;}