本文主要參考MDN|編寫(xiě)高效的CSS聊记、譯文編寫(xiě)高性能高質(zhì)量的CSS代碼楼熄、《高性能網(wǎng)站建設(shè)指南》拗盒、谷歌|優(yōu)化性能础钠、《web前端最佳實(shí)踐》—高性能css等總結(jié)而出恰力。感謝前人的智慧!
[TOC]
前言
CSS代碼重構(gòu)的目的:
我們寫(xiě)CSS代碼時(shí)珍坊,不僅僅只是完成頁(yè)面設(shè)計(jì)的效果牺勾,還應(yīng)該讓CSS代碼易于管理,維護(hù)阵漏。我們對(duì)CSS代碼重構(gòu)主要有兩個(gè)目的:
1驻民、提高代碼性能
2、提高代碼的可維護(hù)性
在這里我主要講解CSS代碼性能提升的一些知識(shí)履怯。
性能優(yōu)化
性能優(yōu)化是一門做減法的藝術(shù)回还。我們首要要盡力簡(jiǎn)化頁(yè)面渲染過(guò)程,然后要使渲染過(guò)程的每一步都盡量高效叹洲。
提高CSS代碼性能主要有兩個(gè)點(diǎn):
1柠硕、提高頁(yè)面的加載性能
提高頁(yè)面的加載性能,簡(jiǎn)單說(shuō)就是減小CSS文件的大小,提高頁(yè)面的加載速度蝗柔,盡可以的利用http緩存
2闻葵、提高CSS代碼性能
不同的CSS代碼,瀏覽器對(duì)其解析的速度也是不一樣的癣丧,如何提高瀏覽器解析CSS代碼的速度也是我們要考慮的
[TOC]
1.CSS選擇器
CSS選擇器具有高效的繼承性槽畔,引用Steve Souders的話, CSS選擇器效率從高到低的排序如下:
- ID選擇器 比如#header
- 類選擇器 比如.promo
- 元素選擇器 比如 div
- 兄弟選擇器 比如 h2 + p
- 子選擇器 比如 li > ul
- 后代選擇器 比如 ul a 7. 通用選擇器 比如 *
- 屬性選擇器 比如 type = “text”
- 偽類/偽元素選擇器 比如 a:hover
以上引用自Steve Souders的Even Faster網(wǎng)站
縱使ID選擇器很快胁编、高效厢钧,但是它也僅僅如此,,盡量不要再css里面使用id嬉橙。從Steve Souders的CSS Test我們可以看出ID選擇器和類選擇器在速度上的差異很小很小早直。
1.1組合選擇器
你可以有一個(gè)標(biāo)準(zhǔn)的選擇器比如#nav,來(lái)選擇任何在此元素下的后代元素市框。此刻霞扬,我們讀這些是從左到右的方式。我們是先找到#nav拾给,然后從它的里面找其他元素祥得。但是瀏覽器解析這些不是這樣的:瀏覽器解析選擇器是從右到左的方式。
如果想要知道更多瀏覽器這樣解析的原因蒋得,請(qǐng)看Stack Overflow上的討論
1.2關(guān)鍵選擇器
渲染樣式時(shí)重要的是選擇器的最后面的部分即為關(guān)鍵選擇器(即用來(lái)匹配目標(biāo)元素的那部分级及,而不是該元素的祖先元素)。在以下例子中將使用該術(shù)語(yǔ)講解额衙。
例如饮焦,在下面規(guī)則中:
a img,
div > h1,
h1 + p {
…
}
關(guān)鍵選擇器為:img
、h1
窍侧、p
CSS規(guī)范并沒(méi)有明確瀏覽器如何去實(shí)現(xiàn)樣式系統(tǒng)县踢,僅僅是說(shuō)明了它們必須這樣做。有鑒于此伟件,不同的樣式系統(tǒng)引擎可能會(huì)擁有完全不同的表現(xiàn)和行為硼啤,特別是 Gecko 與 WebKit, 這兩個(gè)引擎都是開(kāi)源項(xiàng)目斧账,實(shí)現(xiàn)了類似的算法谴返,具有極其相近的優(yōu)缺點(diǎn)。接下來(lái)就讓我們一睹樣式系統(tǒng)如何工作...
[TOC]
2.樣式系統(tǒng)工作原理
2.1樣式系統(tǒng)如何拆分規(guī)則
編寫(xiě)好的CSS代碼咧织,有助提升頁(yè)面的渲染速度嗓袱。本質(zhì)上,引擎需要解析的CSS規(guī)則越少习绢,性能越好渠抹。樣式系統(tǒng)將規(guī)則拆分成四個(gè)主要類別,如下所示,性能依次降低梧却。
- ID規(guī)則
- class規(guī)則
- 標(biāo)簽規(guī)則
- 通用規(guī)則
理解這些分類是十分關(guān)鍵的奇颠,因?yàn)樗鼈兪菢?gòu)建規(guī)則匹配塊的基礎(chǔ)。
ID規(guī)則
即包含了那些將 ID 選擇器作為關(guān)鍵選擇器的規(guī)則篮幢。
示例
#nav {.....}
a#person-intruc {.....}
#nav[href="#"] {.....}
.....
class規(guī)則
如果一個(gè)規(guī)則將一個(gè) class 明確作為它的關(guān)鍵選擇器大刊,那么它就屬于該類別。
示例
.nav {.....}
a.person-intruc {.....}
.nav[href="#"] {.....}
.....
標(biāo)簽規(guī)則
如果既沒(méi)有 class 也沒(méi)有 ID 來(lái)明確作為關(guān)鍵選擇器三椿,那么接下來(lái)的候選者就是 標(biāo)簽 類別。 如果一條規(guī)則將一個(gè)標(biāo)簽作為它的關(guān)鍵選擇器葫辐,那么這條規(guī)則就屬于該類別搜锰。
示例
li {.....}
a > img {.....}
a[href="#"]{.....}
p+ul{.....}
.....
通用規(guī)則
不屬于上面那些類別的規(guī)則都屬于這個(gè)類別。
示例
[hidden="true"] {…} /* A universal rule */
* {…} /* A universal rule */
tree > [collapsed="true"] {…} /* A universal rule */
2.2樣式系統(tǒng)如何匹配規(guī)則
樣式系統(tǒng)從關(guān)鍵選擇器開(kāi)始匹配規(guī)則耿战,然后左移(查找規(guī)則選擇器的任何祖先元素)蛋叼。只要選擇器的子樹(shù)(substree)一直在檢查,樣式系統(tǒng)就會(huì)持續(xù)左移剂陡,直到和規(guī)則匹配狈涮,或者是因?yàn)椴黄ヅ涠艞壴摋l規(guī)則。在這其中涉及到規(guī)則過(guò)濾的基本概念鸭栖,分類的意義恰恰在此歌馍,過(guò)濾掉無(wú)關(guān)的規(guī)則(避免浪費(fèi)時(shí)間去匹配)。
現(xiàn)在問(wèn)題來(lái)了晕鹊,那么什么樣式的CSS代碼能夠更快的匹配松却,不浪費(fèi)時(shí)間呢?
[TOC]
3.高效的CSS代碼編寫(xiě)
3.1避免使用通用規(guī)則和單個(gè)屬性選擇器作為關(guān)鍵選擇器
如
*
溅话、[hidden="true"]
等通用規(guī)則十分浪費(fèi)匹配時(shí)間晓锻。不必要時(shí)盡量不使用。
3.2避免過(guò)度約束
不要用標(biāo)簽名或 classes 來(lái)限定 ID 規(guī)則飞几,不要用標(biāo)簽名限定 class 規(guī)則
如果規(guī)則擁有 ID 選擇器作為其關(guān)鍵選擇器砚哆,則不要為規(guī)則增加標(biāo)簽名。因?yàn)?ID 是唯一的屑墨,增加標(biāo)簽只會(huì)沒(méi)必要地減緩匹配過(guò)程躁锁。
對(duì)于ID的在class這里同樣適用。標(biāo)簽可能會(huì)隨著設(shè)計(jì)改變绪钥,所以僅僅選擇嚴(yán)格語(yǔ)義化的名字作為類名并運(yùn)用是很好的選擇灿里。
【注意】定義過(guò)多id會(huì)使重用性降低,維護(hù)更困難程腹,所以不建議多用id匣吊。
盡量使用最具體的類別,即能一次搞定就一次搞定。解析速度變慢的罪魁禍?zhǔn)拙褪菢?biāo)簽類別中有過(guò)多的規(guī)則色鸳。通過(guò)增加 class 到元素上社痛,我們就可以進(jìn)一步的將這些規(guī)則劃分到 Class 類別中,這將減少用于匹配標(biāo)簽的時(shí)間命雀。
3.3避免后代選擇器
后代選擇器是 CSS 中性能耗用最大的選擇器蒜哀。它的性能開(kāi)銷相當(dāng)大——特別是當(dāng)選擇器在標(biāo)簽或通用類別中。通常我們需要的是 子選擇器吏砂。不僅性能低下而且代碼很脆弱撵儿,html代碼和css代碼嚴(yán)重耦合,html代碼結(jié)構(gòu)發(fā)生變化時(shí)狐血,CSS也得修改淀歇。
差
treehead treerow treecell {…}
略好,但還是差(查看下一條指南)
treehead > treerow > treecell {…}
3.4標(biāo)簽分類的規(guī)則不要包含子選擇器
標(biāo)簽類別的規(guī)則中避免使用子選擇器匈织。否則的話浪默,在該元素出現(xiàn)的所有地方,匹配時(shí)間都將極大延長(zhǎng)(特別是當(dāng)規(guī)則很可能會(huì)被匹配)缀匕。
差
treehead > treerow > treecell {…}
好//采用class規(guī)則
.treecell-header {…}
當(dāng)使用子選擇器時(shí)要十分謹(jǐn)慎纳决。能免則免。
3.5了解依賴?yán)^承乡小,減少代碼量
了解哪些屬性能夠繼承阔加,然后允許它們這樣做!
不可以繼承的屬性:
position劲件、z-index掸哑、top、right零远、bottom苗分、left、clip牵辣、display摔癣、
可以繼承的屬性:
color、font纬向、text-transform择浊、white-space、tab-size逾条、word-break琢岩、word-wrap、overflow-wrap师脂、text-align担孔、text-align-last江锨、text-justify、word-spacing糕篇、letter-spacing啄育、text-indent、line-height拌消、text-size-adjus挑豌、text-shadow、direction墩崩、writing-mode氓英、list-style、list-style-image鹦筹、list-style-position债蓝、list-style-type、table-layout盛龄、border-collapse、border-spacing芳誓、empty-cells余舶、quotes、cursor锹淌、zoom匿值、pointer-events
3.6避免鏈?zhǔn)剑ń患┻x擇符
// bad
.menu.left.icon {..}
// good
.menu-left-icon {..}
3.7盡可能精簡(jiǎn)規(guī)則、盡量不要在選擇符定義過(guò)多層級(jí)赂摆,層級(jí)越少挟憔,同時(shí)也降低了css和dom結(jié)構(gòu)的耦合程度,提高樣式的可維護(hù)性
定義簡(jiǎn)潔的css規(guī)則
使用復(fù)合(緊湊)語(yǔ)法
// bad
.someclass {
padding-top: 20px;
padding-bottom: 20px;
padding-left: 10px;
padding-right: 10px;
background: #000;
background-image: url(../imgs/carrot.png);
background-position: bottom;
background-repeat: repeat-x;
}
// good
.someclass {
padding: 20px 10px 20px 10px;
background: #000 url(../imgs/carrot.png) repeat-x bottom;
}
【特別注意】合理使用簡(jiǎn)寫(xiě)
你可能知道烟号,以下兩行 CSS 代碼并不是等價(jià)的:
background: rebeccapurple;
background-color: rebeccapurple;
前者是簡(jiǎn)寫(xiě)绊谭,它可以確保讓你得到 rebeccapurple 純色背景;但如果你用的是展開(kāi)式的單個(gè)屬性(background-color)汪拥,那這個(gè)元素的背景最終有可能會(huì)顯示為一個(gè)粉色的漸變圖案达传、一張貓的圖片、或任何東西迫筑,因?yàn)橥瑫r(shí)可能會(huì)有一條 background-image 聲明在起作用宪赶。通常在使用展開(kāi)式屬性的寫(xiě)法時(shí),會(huì)遇到這樣的問(wèn)題:展開(kāi)式寫(xiě)法并不會(huì)幫助你清空所有相關(guān)的其他屬性脯燃,從而可能會(huì)干擾你想要達(dá)到的效果搂妻。
了解更多,請(qǐng)參考 CSS 編碼技巧
避免不必要的命名空間
// bad
.someclass table tr.otherclass td.somerule {..}
//good
.someclass .otherclass td.somerule {..}
避免不必要的重復(fù)
// bad
.someclass {
color: red;
background: blue;
font-size: 15px;
}
.otherclass {
color: red;
background: blue;
font-size: 15px;
}
// good
.someclass, .otherclass {
color: red;
background: blue;
font-size: 15px;
}
在上面規(guī)則的基礎(chǔ)上辕棚,合并相同定義(進(jìn)一步合并不同類里的重復(fù)的規(guī)則)欲主,刪除無(wú)效的定義
3.8避免 !important
更多關(guān)于邓厕!important請(qǐng)仔細(xì)閱讀該篇文章!important 的重要性:CSS 不變性。建議閱讀英語(yǔ)版本岛蚤,該篇中文翻譯某些地方感覺(jué)不太恰當(dāng)邑狸。僅僅在不得不使用它的時(shí)候輔助規(guī)則
3.9避免使用CSS表達(dá)式和濾鏡
使用CSS 的expression()通常會(huì)造成多次運(yùn)算。實(shí)際上涤妒,需要用到CSS表達(dá)式的地方单雾,通常能夠找到其他替代方案,所以避免使用CSS表達(dá)式她紫。
那么什么是css expression硅堆?
IE5及其以后版本支持在CSS中使用expression,用來(lái)把CSS屬性和Javascript腳本關(guān)聯(lián)起來(lái)贿讹,這里的CSS屬性可以是元素固有的屬性渐逃,也可以是自定義屬性。就是說(shuō)CSS屬性后面可以是一段Javascript表達(dá)式民褂,CSS屬性的值等于Javascript表達(dá)式計(jì)算的結(jié)果茄菊。在表達(dá)式中可以直接引用元素自身的屬性和方法,也可以使用其他瀏覽器對(duì)象赊堪。
3.10關(guān)于@import
import規(guī)則一定要先于除了@charset的其他任何CSS規(guī)則面殖,盡可能少用該方法引進(jìn)。在編寫(xiě)scss時(shí)如果引進(jìn)文件需要合并需采用@import "xxx.scss"
哭廉。
示例:
#myDiv {
position: absolute;
width: 100px;
height: 100px;
background:#c00;
left: expression(document.body.offsetWidth - 180 "px");//這兒
top: expression(document.body.offsetHeight - -80 "px");//這兒
text-align:center;
line-height:90px;
color:#fff;
}
[TOC]
4.CSS中的圖片處理
4.1不給圖片設(shè)置不符合自身的尺寸(即縮放)
【解釋】:脊僚、同一張圖片可能會(huì)在頁(yè)面不同地方多次使用,比如縮略圖遵绰、正常圖辽幌、大圖。問(wèn)題來(lái)了椿访,如果圖片原始尺寸和實(shí)際需求不同乌企,在使用過(guò)程中就會(huì)存在性能問(wèn)題,利用樣式縮放會(huì)帶來(lái)cpu的額外計(jì)算過(guò)程赎离,增加了圖片在瀏覽器的渲染時(shí)間逛犹,網(wǎng)絡(luò)傳輸過(guò)程也會(huì)占更多帶寬,增加下載時(shí)間梁剔。因此虽画,最佳做法是,為需要的部分單獨(dú)做一套圖片荣病,初始頁(yè)面加載時(shí)就能更快展示码撰。
4.2使用css"雪碧圖"
是將零散的圖片合并成一張大圖,在利用css進(jìn)行背景定位个盆。好處是減少請(qǐng)求數(shù)脖岛,提高了圖片整體的加載速度朵栖。
但它也存在一些缺點(diǎn):
比如,多張圖片合并成大圖柴梆,需要精確計(jì)算陨溅,仔細(xì)的調(diào)整位置,單純手工制作是一件很復(fù)雜的事情绍在。(所幸現(xiàn)在有一些工具可以幫我們做)
另外门扇,維護(hù)過(guò)程復(fù)雜,要盡量讓已有的圖片保持原來(lái)的位置不變偿渡,如果是背景圖的尺寸發(fā)生變化導(dǎo)致原有區(qū)域無(wú)法放置臼寄,那就只好放棄,如果非要在原有位置修改溜宽,則剩余的圖片樣式都需要修改吉拳,是很繁瑣的過(guò)程。新加的圖片最好放在最后面适揉。
使用不當(dāng)會(huì)導(dǎo)致性能問(wèn)題留攒,最大的問(wèn)題就是內(nèi)存消耗。如果制作過(guò)程不做任何的規(guī)劃嫉嘀,隨意擺放稼跳,則可能會(huì)使圖片變得相當(dāng)大,從而很占內(nèi)存吃沪。
建議
- 雪碧圖的尺寸要優(yōu)化好,空白盡可能少什猖;
- 及時(shí)清理不再使用的圖片票彪;
- 將雪碧圖權(quán)重做分離,全局/框架級(jí)的和局部/模塊級(jí)的分離開(kāi)不狮;
- 緩存設(shè)定和更新頻率匹配降铸,如果將每天更新的雪碧圖的緩存設(shè)置到一個(gè)月很容易出問(wèn)題的。
4.3最佳實(shí)踐
1摇零、在項(xiàng)目后期應(yīng)用css sprite技術(shù)
因?yàn)橐话阍陂_(kāi)發(fā)過(guò)程中推掸,會(huì)比較頻繁的修改或者更換圖片,如果這個(gè)時(shí)候使用sprite技術(shù)驻仅,就會(huì)增加很多開(kāi)發(fā)成本谅畅。
2、合理組織“雪碧”圖
如果要把所有的圖片放在一張圖上面噪服,也會(huì)有不妥毡泻,維護(hù)方面也不會(huì)很方便。組織背景圖主要按照模塊和背景圖的風(fēng)格來(lái)劃分粘优。比如仇味,作為展示的縮略圖放在一起呻顽,評(píng)論、點(diǎn)贊丹墨、上下箭頭等圖標(biāo)放在一起等廊遍。
3、控制“雪碧”圖的尺寸和大小
因?yàn)榇蟪叽绲膱D片會(huì)占用大量的內(nèi)存贩挣,所以要控制在合理尺寸喉前,推薦長(zhǎng)寬相乘不超過(guò)2500,大小在200kb內(nèi)
4揽惹、合理控制背景圖單元間的距離及背景圖位置
這個(gè)原則是為了防止在背景圖比元素大小更小的時(shí)候被饿,區(qū)域出現(xiàn)別的無(wú)關(guān)背景圖
5、借助相關(guān)工具處理sprite