在前端面試中最常見的問(wèn)題就是頁(yè)面優(yōu)化和緩存(貌似也是頁(yè)面優(yōu)化),被問(wèn)了幾次后心虛的不行,平然平時(shí)多少會(huì)用到一些,但突然問(wèn)我,很難把自己知道的都說(shuō)出來(lái)。頁(yè)面優(yōu)化明顯不是一兩句能夠說(shuō)完的,這兩天總結(jié)了一下CSS相關(guān)的優(yōu)化知識(shí),寫篇博客梳理一下,還望大家多多指教
關(guān)于CSS的優(yōu)化工作主要從兩個(gè)方面著手
網(wǎng)絡(luò)性能:把CSS寫到字節(jié)數(shù)最少,加快下載速度,自然可以讓頁(yè)面渲染的更快一些
語(yǔ)法性能:同樣都能實(shí)現(xiàn)某些效果,但并不是所有的方式效果都相同,我們看過(guò)不少關(guān)于JavaScript方面的語(yǔ)法優(yōu)化知識(shí),其實(shí)CSS里面也有一些
CSS壓縮
CSS壓縮并不是什么高端的姿勢(shì),但卻很有用,其原理很簡(jiǎn)單,就是把我們CSS中沒用的空白符等刪去,達(dá)到縮減字符個(gè)數(shù)的目的
我們有這樣一段CSS腳本
.test{ background-color:#ffffff; background-image:url(a.jpg); }
經(jīng)過(guò)壓縮后會(huì)變成這樣
.test{ background-color:#fff; background-image:url(a.jpg)}
當(dāng)然高級(jí)些的壓縮工具也會(huì)幫我們優(yōu)化一些語(yǔ)法,提供很多選項(xiàng),讓我們的壓縮更有控制,之前在的公司不采用CSS壓縮,所以我沒有什么實(shí)踐經(jīng)驗(yàn),自己寫東西常用的是YUI Compressor,有很多在線版的很方便
YUI Compressor
CSS Compressor
CSS drive
Clean CSS
大家有什么好的資源希望也推薦一下
gzip壓縮
Gzip是一種流行的文件壓縮算法,現(xiàn)在的應(yīng)用十分廣泛,尤其是在Linux平臺(tái),這個(gè)不止是對(duì)CSS,當(dāng)應(yīng)用Gzip壓縮到一個(gè)純文本文件時(shí),效果是非常明顯的,大約可以減少70%以上的文件大。ㄟ@取決于文件中的內(nèi)容)。想進(jìn)一步了解gzip看看維基百科。
在沒有g(shù)zip壓縮的情況下,Web服務(wù)器直接把html頁(yè)面、CSS腳本、js腳本發(fā)送給瀏覽器,而支持gzip的Web服務(wù)器將把文件壓縮后再發(fā)給瀏覽器,瀏覽器(支持gzip)在本地進(jìn)行解壓和解碼,并顯示原文件。這樣我們傳輸?shù)奈募止?jié)數(shù)減少了,自然可以達(dá)到網(wǎng)絡(luò)性能優(yōu)化的目的。gzip壓縮需要服務(wù)器的支持,所以我們需要在服務(wù)器端進(jìn)行配置
在IIS上啟用Gzip壓縮(HTTP壓縮)
apache啟用gzip壓縮方法
Nginx Gzip 壓縮配置
當(dāng)然除了gzip壓縮,緩存也是我們需要注意的,這和CSS優(yōu)化關(guān)系不大了,在說(shuō)web優(yōu)化的時(shí)候再說(shuō)
合寫CSS
除了壓縮的方式,我們還可以通過(guò)少寫CSS屬性來(lái)達(dá)到減少CSS字節(jié)的目的,拿個(gè)最常見的例子
.test{ background-color: #000; background-image: url(image.jpg); background-position: left top; background-repeat: no-repeat; }
我們可以改寫一下上面的CSS,達(dá)到同樣的效果
.test{ background: #000 url(image.jpg) top left no-repeat; }
在CSS中還有很多類似的屬性可以合寫
font
{font-style: oblique; font-weight: bold; font-size: 16px; font-family: Helvetica, Arial, Sans-Serif;} {font: oblique bold 16px Helvetica, Arial, Sans-Serif;}
margin/padding
{margin-top: 5px; margin-right: 10px; margin-bottom: 20px; margin-left: 15px;} {margin: 5px 10px 20px 15px;}
{padding-top: 5px; padding-right: 10px; padding-bottom: 5px; padding-left: 10px;} {padding: 5px 10px} {padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px;} {padding:5px;}
background
{background-color: #000; background-image: url(image.jpg); background-position: left top; background-repeat: no-repeat;} {background: #000 url(image.jpg) top left no-repeat;}
border
{border-width: 2px; border-style: solid; border-color: #000;} {border: 2px solid #000;}{border-top: 2px; border-right: 5px; border-left: 10px; border-bottom: 3px;} {border: 2px 5px 10px 3px;}
另外CSS3添加的很多屬性如transform、animation相關(guān)的都可以合寫,不一一列舉,大家用的時(shí)候要注意
利用繼承
CSS的繼承機(jī)制也可以幫我們?cè)僖欢ǔ潭壬峡s減字節(jié)數(shù),我們知道CSS有很多屬性是可以繼承的即在父容器設(shè)置了默寫屬性,子容器會(huì)默認(rèn)也使用這些屬性,因此如果我們希望全文字體尺寸是14px,大可不必為每個(gè)容器設(shè)置,只需要在body上設(shè)置就可以了。應(yīng)用這個(gè)技巧,把CSS屬性在可能的情況下提到父容器是可以幫我們節(jié)省CSS字節(jié)的,順便說(shuō)一下哪些屬性可以繼承
所有元素可繼承:visibility和cursor
內(nèi)聯(lián)元素可繼承:letter-spacing、word-spacing、white-space、line-height、color、font、 font-family、font-size、font-style、font-variant、font-weight、text- decoration、text-transform、direction
塊狀元素可繼承:text-indent和text-align
列表元素可繼承:list-style、list-style-type、list-style-position、list-style-image
表格元素可繼承:border-collapse
不可繼承的:display、margin、border、padding、background、height、min-height、max- height、width、min-width、max-width、overflow、position、left、right、top、 bottom、z-index、float、clear、table-layout、vertical-align、page-break-after、 page-bread-before和unicode-bidi
css中可以和不可以繼承的屬性
抽離、拆分CSS,不加載所有CSS
抽離CSS是指把一些通用的CSS放到一個(gè)文件內(nèi),而不是寫道各個(gè)頁(yè)面,這樣一次下載后,其它頁(yè)面用到的時(shí)候就可以利用緩存了,減少不必要的重復(fù)下載。
應(yīng)用抽離原則,在很多時(shí)候我們把頁(yè)面通用的CSS寫到了一個(gè)文件,這樣加載一次后就可以利用緩存,但這樣做并不適合所有場(chǎng)景,以前我寫CSS把一些前端插件用的CSS全寫到了一個(gè)頁(yè)面,但是有時(shí)候頁(yè)面只會(huì)用一個(gè)Dialog、有的頁(yè)面只用到了一個(gè)TreeView,但卻把十多個(gè)插件的CSS都下載到了頁(yè)面,這就是問(wèn)題了,所以雖然把CSS寫道一個(gè)文件可以減少http請(qǐng)求,但像剛才的這種情況是不應(yīng)該這樣做的,對(duì)一些所有頁(yè)面都會(huì)用到的我們可以這樣做,所以我們?cè)诔殡x和拆分的時(shí)候可要想好了。
CSS sprites
這個(gè)其實(shí)算不上是CSS優(yōu)化,應(yīng)該說(shuō)是web優(yōu)化用到了CSS的技巧,順便提一下,有興趣同學(xué)可以看看使用CSS sprites減少HTTP請(qǐng)求。
網(wǎng)絡(luò)性能方面能想到的就暫時(shí)這么多了,希望大家?guī)兔χ刚脱a(bǔ)充,看一些語(yǔ)法上的性能優(yōu)化
CSS放在head中,減少repaint和reflow
相信做web的同學(xué)都知道這條建議,但為什么CSS放在頁(yè)面頂部有利于網(wǎng)頁(yè)優(yōu)化呢?瀏覽器渲染頁(yè)面大概是這樣的,當(dāng)瀏覽器從上到下一邊下載html生成DOM tree一邊根據(jù)瀏覽器默認(rèn)及現(xiàn)有CSS生成render tree來(lái)渲染頁(yè)面,當(dāng)遇到新的CSS的時(shí)候下載并結(jié)合現(xiàn)有CSS重新生成render tree,剛才的渲染工作就白費(fèi)了,如果我們把所有CSS都放到頁(yè)面頂部,這樣就沒有重新渲染的過(guò)程了。對(duì)瀏覽器工作原理有興趣的同學(xué)可以看看神文
瀏覽器的工作原理:新式網(wǎng)絡(luò)瀏覽器幕后揭秘,相信會(huì)對(duì)瀏覽器工作原理有深入的認(rèn)識(shí)。
類似的我們知道了這個(gè)也應(yīng)該在腳本中注意盡量減少repaint和reflow,什么情況會(huì)導(dǎo)致這兩種情況呢
reflow:當(dāng)DOM元素出現(xiàn)隱藏/顯示、尺寸變化、位置變化的時(shí)候都會(huì)讓瀏覽器重新渲染頁(yè)面,之前渲染工作白費(fèi)了
repaint:當(dāng)元素的背景顏色、邊框顏色不引起reflow的變化是會(huì)讓瀏覽器重新渲染該元素。貌似還可以接受,但如果我們?cè)陂_始就定義好了,不讓瀏覽器重復(fù)工作就更好了。
不用CSS表達(dá)式
無(wú)論怎樣生成的CSS,最終我們放到頁(yè)面上得是靜態(tài)普通文本,沒有變量、計(jì)算神馬的,CSS表達(dá)式是一種動(dòng)態(tài)設(shè)置CSS屬性的東東,被IE5-IE8支持,看一個(gè)大家常用的例子
body { background-color: expression((new Date()).getHours()%2?"#B8D4FF":"#F08A00"); }
這樣我們賦予了CSS類似JavaScript的功能,CSS表達(dá)式非常強(qiáng)大,甚至可以使用CSS表達(dá)式實(shí)現(xiàn) min-width 屬性,隔行換色,模擬 :hover, :before, :after 等偽類,看起來(lái)能解決很多IE下的瀏覽器兼容性等問(wèn)題,但是其帶來(lái)的副作用超出我們的想象,這條CSS規(guī)則并不是只運(yùn)行一次,為了確保有效性,CSS表達(dá)式會(huì)進(jìn)行頻繁的求值,當(dāng)改變窗口大小,滾動(dòng)頁(yè)面甚至移動(dòng)鼠標(biāo)都會(huì)觸發(fā)表達(dá)式進(jìn)行求值,如此頻繁的求值以至于瀏覽器的性能收到嚴(yán)重的影響。據(jù)《高性能網(wǎng)站建設(shè)建議》中的測(cè)試其執(zhí)行次數(shù)遠(yuǎn)遠(yuǎn)超出我們想象,感興趣同學(xué)可以進(jìn)去看看,我們的建議就試盡量避免甚至不要使用CSS表達(dá)式。
不亂用CSS reset或?qū)傩栽O(shè)置
在網(wǎng)站建設(shè)中我們經(jīng)常使用一些CSS reset,達(dá)到跨瀏覽器統(tǒng)一的目的,但是很多時(shí)候我們的CSS reset過(guò)于臃腫,主要有兩個(gè)問(wèn)題
把很多瀏覽器對(duì)元素的默認(rèn)屬性有設(shè)置了一邊,比如div的padding和margin為0啊什么的,這是沒有必要的
把一些很不常用的元素的設(shè)置也寫進(jìn)了CSS reset,如 ruby這樣的元素
前幾天寫了篇關(guān)于CSS reset的博客常見標(biāo)簽的默認(rèn)屬性值及相互作用——關(guān)于CSS reset的思考,都是一些個(gè)人認(rèn)識(shí),希望大家批評(píng)指正
避免適用通配符或隱式通配符
CSS中的*代表通配符,雖然好用但使用不當(dāng)這也是一個(gè)惡魔,比如
body * {padding:0;margin:0;}
我們以為這是對(duì)body的子結(jié)點(diǎn)都設(shè)置一些屬性,但因?yàn)镃SS繼承特性的原因,頁(yè)面所有元素都會(huì)接受這個(gè)規(guī)則,對(duì)于復(fù)雜的頁(yè)面在性能上的影響還是很大的,這并不是說(shuō)不能使用通配符,而是說(shuō)使用的時(shí)候要注意范圍。相信這個(gè)規(guī)則大家都知道,但是有一些隱式的通配符也需要我們的注意,比如
:visible{ padding:0; }
這樣的幾乎就和通配符一樣,在使用的時(shí)候一定要注意范圍限制問(wèn)題
避免層級(jí)或過(guò)度限制的CSS
估計(jì)web開發(fā)的同學(xué)都看過(guò)MDN上Writing efficient CSS或者其各種翻譯版本,文中總結(jié)了幾點(diǎn)在書寫CSS selector的意見,搞明白文中建議的一個(gè)前提是得知道CSS是從右到左解析的,而不是我們認(rèn)為的從左到右,關(guān)于為什么這樣做肯定是因?yàn)楦咝,不明就里的同學(xué)可以上網(wǎng)搜一下相關(guān)知識(shí)。
不要用標(biāo)簽或 class 來(lái)限制 ID 規(guī)則
這個(gè)應(yīng)該是個(gè)常識(shí),但很多同學(xué)都會(huì)誤用,寫出#test.info或者div#test這樣的選擇器,這個(gè)只能說(shuō)是畫蛇添足,id已經(jīng)可以唯一而且最快的定位一個(gè)元素了
不要用標(biāo)簽名限制 class 規(guī)則
這個(gè)估計(jì)被誤用的更多,如div.info這樣的寫法,其實(shí)我們可以直接寫為.info,從右到左解析的原因可以知道為什么其低效,如果直接使用class不能達(dá)到目的,一般情況下應(yīng)該是class設(shè)計(jì)的有問(wèn)題,CSS需要重構(gòu)了
盡量使用最具體的類別、避免后代選擇器、屬于標(biāo)簽類別的規(guī)則永遠(yuǎn)不要包含子選擇器
這三條規(guī)則是想通的,因?yàn)閺淖蟮接医馕鲫P(guān)系,在CSS選擇器中后代選擇器非但沒有幫我們加快CSS查找,反而后代選擇器是 CSS 中耗費(fèi)最昂貴的選擇器。 它的耗費(fèi)是極其昂貴的—特別是當(dāng)選擇器在標(biāo)簽或通用類別中,作者給的建議是當(dāng)使用子選擇器時(shí)要十分謹(jǐn)慎,能免則免。其開銷可見一斑了。
對(duì)此我們可以通過(guò)具體類別——使用單一或盡量少的class解決。
最后
平常用到和了解的關(guān)于優(yōu)化CSS達(dá)到頁(yè)面優(yōu)化的手段就這些了,希望大家給出意見和補(bǔ)充。