CSS 寫作建議和性能優(yōu)化小結(jié)

作者:守候
文章轉(zhuǎn)載自:https://segmentfault.com/a/1190000011390896

1.前言

還有幾天就到國(guó)慶中秋了,快要放假了,先祝大家節(jié)日快樂!之前寫過 JS 的寫作建議和技巧,那么今天就來聊聊 CSS 吧!

說到 CSS,每一個(gè)網(wǎng)頁都離不開 CSS,但是對(duì)于 CSS,很多開發(fā)者的想法就是,CSS 只要能用來布局,把效果圖排出來就可以了,其它的細(xì)節(jié)或者優(yōu)化,不需要怎么考慮。但是我覺得 CSS 可不只是把頁面的布局完成就是完事的,還需要考慮很多細(xì)節(jié)有優(yōu)化,更不會(huì)像大家想得那么簡(jiǎn)單。在學(xué)習(xí)當(dāng)中,如果發(fā)現(xiàn)什么技巧或者優(yōu)化的點(diǎn),我也會(huì)學(xué)以致用!

那么今天,就分享下我總結(jié)的 CSS 寫作建議和性能優(yōu)化的一些問題!希望能幫讓大家對(duì)神奇的 CSS 有一個(gè)新認(rèn)識(shí)。當(dāng)然,如果大家覺得還有什么其它的建議,歡迎指點(diǎn)!

2.CSS 渲染規(guī)則

首選,關(guān)于CSS 渲染的規(guī)則,大家可能都知道,是從右到左的渲染!如下栗子:

.nav h3 a{font-size: 14px;}

渲染過程大概是:首先找到所有的a,沿著a的父元素查找h3,然后再沿著h3,查找.nav。中途找到了符合匹配規(guī)則的節(jié)點(diǎn)就加入結(jié)果集。如果找到根元素html都沒有匹配,則不再遍歷這條路徑,從下一個(gè)a開始重復(fù)這個(gè)查找匹配(只要頁面上有多個(gè)最右節(jié)點(diǎn)為a)。

參考:CSS選擇器從右向左的匹配規(guī)則

3.嵌套層級(jí)不要超過 3 級(jí)

一般情況下,元素的嵌套層級(jí)不能超過 3 級(jí),過度的嵌套會(huì)導(dǎo)致代碼變得臃腫、沉余、復(fù)雜,導(dǎo)致 CSS 文件體積變大,造成性能浪費(fèi),影響渲染的速度,而且過于依賴 HTML 文檔結(jié)構(gòu)。這樣的 CSS 樣式,維護(hù)起來,極度麻煩,如果以后要修改樣式,可能要使用!important覆蓋。

4.樣式重置

這個(gè)我目前保持中立意見,因?yàn)榭粗W(wǎng)上的文章,有些人支持使用樣式重置,有些人不支持使用,誰也說服不了誰。我自己的情況,我有使用樣式重置,但是是比較簡(jiǎn)單的一個(gè)總結(jié),代碼如下!

body,dl,dd,h1,h2,h3,h4,h5,h6,p,form,ol,ul {
  margin: 0;
  padding: 0;
}
h1, h2, h3, h4, h5, h6 {
  font-weight: normal;
}

ol, ul {
  list-style: none;
}
h1{
  font-size: 24px;
}

h2{
  font-size: 20px;
}

h3{
  font-size: 18px;
}

h4 {
  font-size: 16px;
}

h5{
  font-size: 14px;
}

h6{
  font-size: 12px;
}

5.樣式級(jí)別

首先,CSS 樣式級(jí)別整理如下:

!important > 行內(nèi)樣式 > ID 樣式 > Class 樣式 > 標(biāo)簽名樣式。

然后有一點(diǎn)要提一下就是,組合選擇器使用權(quán)值會(huì)疊加的。比如 ID 的權(quán)值是100,Class 是10,標(biāo)簽名是 1(其它不清楚了)!那么div.test-class權(quán)值就是 11,div#test就是 101.

比如有一個(gè) div:

<div id="test" class="test-class" style="color:green;"></div>

那么樣式權(quán)值方面就是:

  • div {color: red !improtant;}(大于下面的一切)
  • <div id="test" class="test-class" style="color:black;"></div>(大于 111)
  • div#test.test-class(111)
  • #id.test-class(110)
  • div#test(101)
  • #test(100)
  • div.test-class(11)
  • .test-class(10)
  • div(1)
  • *(小于 1)

6.inline-block 的邊距

不解釋,看圖:

上面幾個(gè)p元素marginpadding都為0,但是還有邊距。這個(gè)的解決方案有兩種:

  1. 刪除代碼之前的空行空格

display:inline-block的元素之前的空行都刪除掉,如下寫法:

  1. 父元素font-size設(shè)置為0,這個(gè)直接看圖:

7.圖片要設(shè)置 width 和 height

如果頁面有使用img標(biāo)簽,那么img很建議設(shè)置widthheight。目的是為了在網(wǎng)速差或者其它原因加載不出圖片的時(shí)候,保證布局不會(huì)亂。如下栗子,一個(gè)很普通的布局。

但是萬一出現(xiàn)什么情況,圖片加載不出來的話,建議的處理方式是第一種,顯示一張默認(rèn)圖片,即使不顯示默認(rèn)圖片,也讓圖片有一個(gè)占位的作用,保證布局不會(huì)亂!

如果圖片加載不出,img又沒有設(shè)置widthheight的話,就會(huì)像下面這樣,布局亂了!

關(guān)于設(shè)置widthheight,我順便說幾點(diǎn):

  1. PC 站,建議在img標(biāo)簽的屬性設(shè)置widthheight。這樣避免加載不出 CSS 而錯(cuò)位;
  2. 手機(jī)站,建議用 CSS 設(shè)置imgwidthheight,因?yàn)槭謾C(jī)站要做適配,在屬性設(shè)置widthheight不靈活,比如使用rem布局,在屬性那里設(shè)置不了widthheight;
  3. 如果圖片不固定,但是有一個(gè)max-widthmax-height,那么建議在img的父元素設(shè)置widthheightimg根據(jù)父元素的widthheight設(shè)置max-widthmax-height。

8.任意元素垂直居中

這里只放圖,不解釋:

8-1. table-cell

8-2. flex

8-3. position,transform

8-4. position,margin

這個(gè)方式不推薦使用,因?yàn)檫@個(gè)寫法,.div2的寬高必須要設(shè)置,否則就是 100%,比如設(shè)置了top:0;bottom:0;效果和設(shè)置height:100%;是一樣的。如果想要避免,就必須要設(shè)置height

9.圖片預(yù)加載

這里說的預(yù)加載,不是懶加載。首先根據(jù)我個(gè)人理解科普下,懶加載和預(yù)加載的區(qū)別。

  • 懶加載:頁面加載的時(shí)候,先加載一部分內(nèi)容(一般是先加載首屏內(nèi)容),其它內(nèi)容等到需要加載的時(shí)候再進(jìn)行加載。
  • 預(yù)加載:頁面加載的時(shí)候,先加載一部分內(nèi)容(一般是先加載首屏內(nèi)容),其它內(nèi)容等到先加載的一部分內(nèi)容(一般是首屏內(nèi)容)加載完了,再進(jìn)行加載。

兩種方式,都是為了減少用戶進(jìn)入網(wǎng)站的時(shí)候,更快的看到首屏的內(nèi)容。

下面栗子,將這#preloader這個(gè)元素加入到到 HTML 中,就可以實(shí)現(xiàn)通過 CSS 的background屬性將圖片預(yù)加載到屏幕外的背景上。只要這些圖片的路徑保持不變,當(dāng)它們?cè)?Web 頁面的其他地方被調(diào)用時(shí),瀏覽器就會(huì)在渲染過程中使用預(yù)加載(緩存)的圖片。簡(jiǎn)單、高效,不需要任何 JavaScript。

#preloader {
    /*需要預(yù)加載的圖片*/
    background: url(image1.jpg) no-repeat,url(image2.jpg) no-repeat,url(image3.jpg) no-repeat;
    width: 0px;
    height: 0px;
    display: inline;
}

但是這樣會(huì)有一個(gè)問題,因?yàn)?code>#preloader預(yù)加載的圖片,會(huì)和頁面上的其他內(nèi)容一起加載,增加了頁面的整體加載時(shí)間。所以需要用 JS 控制。

function preloader(urlArr,obj) {
    var bgText='';
    for(var i=0,len=urlArr.length;i<len;i++){
        bgText+='url('+urlArr[i]+') no-repeat,';
    }
    obj.style.background=bgText.substr(0,bgText.length-1);
}
window.onload = function() {
   preloader(['image1.jpg','image2.jpg','image3.jpg'],document.getElementById('preloader'));
}

原理也很簡(jiǎn)單,就是先讓首屏的圖片加載完,然后再加載其它的圖片。通過給#preloader設(shè)置背景圖片,加載所需要的圖片,然后頁面上需要加載這些圖片的時(shí)候,就直接從緩存里面拿圖片,不需要通過 HTTP 請(qǐng)求獲取圖片,這樣加載就很快。

10.慎用 * 通配符

在做網(wǎng)頁的時(shí)候,經(jīng)常會(huì)使用下面兩種方式重置樣式,以此來消除標(biāo)簽的默認(rèn)布局和不同瀏覽器對(duì)于同一個(gè)標(biāo)簽的渲染。

*{margin:0;padding:0;}

上面這種方式,代碼少,但是性能差,因?yàn)殇秩镜臅r(shí)候,要匹配頁面上所有的元素。很多基礎(chǔ)樣式?jīng)]有marginpadding的元素,比如divli等都被匹配,完全沒必要。下面看另一種方式:

body,dl,dd,h1,h2,h3,h4,h5,h6,p,form,ol,ul{margin:0;padding:0;}

這種方式,代碼稍微多,但是性能比上面的方式好。在渲染的時(shí)候,只匹配body,dl,dd,h1,h2,h3,h4,h5,h6,p,form,ol,ul這里面的元素,這些元素帶有marginpadding,需要重置。

再看例子:

.test * {color: red;}

匹配文檔中所有的元素,然后分別向上逐級(jí)匹配classtest的元素,直到文檔的根節(jié)點(diǎn):

.test a {color: red;}

匹配文檔中所有a的元素,然后分別向上逐級(jí)匹配classtest的元素,直到文檔的根節(jié)點(diǎn)。

兩種方式,哪種更好不言而喻,所以在開發(fā)的時(shí)候,建議避免使用通配選擇器。

11.合并、壓縮 CSS

這個(gè)沒什么好解釋的,就是壓縮和合并 CSS。

首先壓縮 CSS,除了使用工具,比如 Gulp、Webpack 等把代碼壓縮,把空格和換行都去掉。還有一個(gè)建議就是屬性簡(jiǎn)寫。

比如:

margin-top:0;
margin-right:10px;
margin-bottom:10px;
margin-left:10px;
background-image: url('test.jpg');
background-position: top center;
background-repeat: no-repeat;
border-width:1px;
border-style:solid;
border-color:#000;
color:#0099FF;

可以換成下面的:

margin:0 10px 10px 10px;
background: url('test.jpg') no-repeat top center;
border:1px solid #000;
color:#09F;       

至于合并的時(shí)候,我按照自己的開發(fā)習(xí)慣給幾個(gè)建議:

  1. 合并公用的樣式。比如項(xiàng)目的頭部、底部、側(cè)邊欄這些,一般都是公用的,這些可以寫在一個(gè)公用樣式表上,比如main.css;
  2. 上面所說的main.css是每一個(gè)頁面都需要引入,而樣式重置表reset.css也是每一個(gè)頁面都需要用到的,那么建議main.cssreset.css合并成一個(gè)文件,給頁面引入,減少請(qǐng)求;
  3. 每個(gè)頁面對(duì)應(yīng)的樣式為獨(dú)立的文件。比如首頁對(duì)應(yīng)的是index.css,產(chǎn)品列表頁對(duì)應(yīng)的樣式是product-list.css。那么index.css就只在首頁引入,其它頁面不引入,因?yàn)橐爰儗倮速M(fèi)請(qǐng)求資源,其他頁面對(duì)應(yīng)的樣式也是這個(gè)處理方式。index.css、product-list.css等其它頁面的樣式就保留單獨(dú)的文件,不作合并處理。

12.CSS 在 head 引入

瀏覽器在所有的 stylesheets 加載完成之后,才會(huì)開始渲染整個(gè)頁面。在此之前,瀏覽器不會(huì)渲染頁面里的任何內(nèi)容,頁面會(huì)一直呈現(xiàn)空白。這也是為什么要把 stylesheet 放在頭部的原因。如果放在 HTML 頁面底部,頁面渲染就不僅僅是在等待 stylesheet 的加載,還要等待 HTML 內(nèi)容加載完成,這樣一來,用戶看到頁面的時(shí)間會(huì)更晚。

13.避免使用 @import

CSS 樣式文件有兩種引入方式,一種是link元素,另一種是@import。在這里,我建議就是避免使用@import。因?yàn)?code>@import會(huì)影響瀏覽器的并行下載,使得頁面在加載時(shí)增加額外的延遲,增添了額外的往返耗時(shí)。而且多個(gè)@import可能會(huì)導(dǎo)致下載順序紊亂。

比如一個(gè) CSS 文件index.css包含了以下內(nèi)容:@import url("reset.css")。那么瀏覽器就必須先把index.css下載、解析和執(zhí)行后,才下載、解析和執(zhí)行第二個(gè)文件reset.css。簡(jiǎn)單的解決方法是使用<link>替代@import

14.從 PSD 文件思考怎么寫代碼

接到效果圖,先不用著急切圖,先看下 PSD 文件。思考下怎么排版,那些模塊可以做成公用的模塊,模塊應(yīng)該怎么命名,寫樣式等。當(dāng)我們拿到設(shè)計(jì)師給的 PSD 時(shí),首先不要急于寫 CSS 代碼,首先對(duì)整個(gè)頁面進(jìn)行分析,先思考下面幾點(diǎn):

  1. 分析頁面有哪些模塊是公用的。常見公用模塊有頭部、底部、菜單欄、懸浮按鈕等;
  2. 分析模塊有什么樣式,把公用的樣式提取出來,公用樣式包括公用的狀態(tài)樣式。比如按鈕、輸入框、下拉框等公用的選中狀態(tài),禁用狀態(tài)的樣式等。

15.小圖標(biāo)的處理方案

一個(gè)網(wǎng)站肯定會(huì)有很多個(gè)小圖標(biāo),對(duì)于這些小圖標(biāo),目前的解決方案有兩個(gè),CSS Sprite(雪碧圖),字體圖標(biāo),把圖片轉(zhuǎn)成 base64。下面對(duì)比一下這兩種方式:

  • CSS Sprite:把所有 icon 圖片合成一張 png 圖片,使用的是在對(duì)節(jié)點(diǎn)設(shè)置寬高,加上bacgroud-position。以背景圖方式顯展示需要的 icon,如果一個(gè)網(wǎng)站有 20 圖標(biāo),那么就要請(qǐng)求 20 次。使用 CSS Sprite,只需要請(qǐng)求一次,大大的減少了 HTTP 請(qǐng)求。缺點(diǎn)就是管理不靈活,如果需要新增一個(gè)圖標(biāo),都需要改合并圖片的源文件,圖標(biāo)定位也要規(guī)范,不然容易干擾圖片之間的定位;
  • 字體圖標(biāo):簡(jiǎn)單粗暴的理解就是把所有的圖標(biāo)當(dāng)成一個(gè)字體處理,這樣不用去請(qǐng)求圖片。一般是使用 class 來定義圖標(biāo),要替換圖標(biāo)時(shí),只需更換樣式名,管理方便,語意明確,靈活放大縮小,并且不會(huì)造成失真,但是只支持單色的圖片。
  • base64:另一種方案就是把小的 icon 圖片轉(zhuǎn)成 base64 編碼,這樣可以不用去請(qǐng)求圖片,把 base64 編碼直接整合到 JS 或者 CSS 里面,可以防止因?yàn)橐恍┫鄬?duì)路徑,或者圖片被不小刪除了等問題導(dǎo)致圖片 404 錯(cuò)誤。但是找個(gè)方式會(huì)生成一大串的 base64 編碼。一般來說,8K 以下的圖片才轉(zhuǎn)換成 base64 編碼。如果把一張 50K 的圖片轉(zhuǎn)成 base64 編碼,那么會(huì)生成超過 65000 個(gè)字符的 base64 編碼,字符的大小就已經(jīng)是將近 70K 了!建議就是:8K 以下的圖片才轉(zhuǎn)換成 base64 編碼。

16.不要在 ID 選擇器前面進(jìn)行嵌套或?qū)憳?biāo)簽

  1. ID 在頁面上本來就是唯一的,而且人家權(quán)值那么大,前方嵌套(.content #test)完全是浪費(fèi)性能,以及多寫一些沒有意義的代碼。這個(gè)雖然是一句話,但是還是有人犯這樣的錯(cuò)。
  2. 除了嵌套,在 ID 的前面也不需要加標(biāo)簽或者其它選擇器。比如div#test或者.test#test。這兩種方式完全是多余的,理由就是 ID 在頁面就是唯一的。前面加任何東西都是多余的!

17.把常用樣式抽封裝成公用樣式

把長(zhǎng)段相同樣式提取出來作為公用樣式使用,比如常用的清除浮動(dòng),單行超出顯示省略號(hào),多行超出省略號(hào)等。

如下栗子:

/*超出省略號(hào)*/
/*<p class='text-ellipsis'></p>*/
.text-ellipsis{
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/*清除浮動(dòng)*/
/*<div class='clearfix'></div>*/
.clearfix:after {
    display: block;
    content: '';
    clear: both;
    height:0;
}

18.CSS3 動(dòng)畫的優(yōu)化

在我之前一篇文章(移動(dòng) Web 開發(fā)問題和優(yōu)化小結(jié)),也有寫過關(guān)于這個(gè)的優(yōu)化建議,之前說的兩個(gè)建議是:

  1. CSS3 動(dòng)畫或者過渡盡量使用transformopacity來實(shí)現(xiàn)動(dòng)畫,不要使用lefttop;
  2. 動(dòng)畫和過渡能用CSS3解決的,就不要使用JS。如果是復(fù)雜的動(dòng)畫可以使用CSS3+JS(或者HTML5+CSS3+JS)配合開發(fā),效果只有想不到,沒有做不到。

下面補(bǔ)充一個(gè):動(dòng)畫不宜過多,尤其是手機(jī)網(wǎng)站,否則會(huì)出現(xiàn)性能的問題.比如 CPU 一下子就被占用滿了,掉幀等。而且,不建議給每一個(gè)元素都使用硬件加速。

參考鏈接:

19.Body 設(shè)置最小寬度

這個(gè)是在 PC 站會(huì)出現(xiàn)的問題,應(yīng)該大家都知道。下面簡(jiǎn)單說一下!

比如下面的栗子,一個(gè)網(wǎng)站,頁面內(nèi)容寬度是 1200px??粗苷#瑳]什么特別:

如果這個(gè)時(shí)候,把頁面窗口縮小。小于 1200px,頁面出現(xiàn)滾動(dòng)條,然后把滾動(dòng)條拖到最右邊:

這樣是不是就發(fā)現(xiàn),頂部的圖片和背景有一部分是斷層了!解決這個(gè)問題也很簡(jiǎn)單,就是給body加上min-width。值就是頁面寬度的值:body{min-width:1200px;}

重復(fù)上一步操作,無論怎么改變?yōu)g覽器窗口大小,都是正常的:

之所以會(huì)出現(xiàn)這樣的問題,是因?yàn)?,比如窗口縮小到 900px 的時(shí)候,小于內(nèi)容寬度的 1200px。就是出現(xiàn)橫向的滾動(dòng)條,但是body的寬度是 900px。這個(gè)時(shí)候,如果有元素(比如圖片的灰色區(qū)域和粉紅色的圖片)是相對(duì)bodywidth設(shè)置 100%,那么實(shí)際上這些元素的寬度也就是 900px。所以會(huì)出現(xiàn)斷層那些的視覺!解決方式就是給body加上min-width。讓body的寬度最小不會(huì)小于內(nèi)容的寬度!

20.小結(jié)

關(guān)于我對(duì) CSS 寫作建議和性能優(yōu)化的一個(gè)總結(jié),就到這里了。CSS 絕對(duì)不是那種只要能用就行,或者只要能用 CSS 把布局弄好就行的一門語言。CSS 給我的感覺,就是上手很簡(jiǎn)單,但是如果想用好 CSS,還是得花時(shí)間去研究。CSS 或者 CSS3,能夠優(yōu)化的東西還有很多,用好 CSS 或者 CSS3 能夠少寫很多 JS 代碼,做出來的東西也是很神奇,大家還是得繼續(xù)學(xué)習(xí)當(dāng)中的知識(shí)。

如果大家覺得我文章有哪個(gè)地方寫得不好,寫錯(cuò)了,歡迎指正。如果有什么其它的建議,歡迎指點(diǎn),讓大家互相交流,互相學(xué)習(xí),一起進(jìn)步!最后,祝大家節(jié)日快樂!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 14,124評(píng)論 1 92
  • 選擇qi:是表達(dá)式 標(biāo)簽選擇器 類選擇器 屬性選擇器 繼承屬性: color,font,text-align,li...
    wzhiq896閱讀 2,114評(píng)論 0 2
  • 選擇qi:是表達(dá)式 標(biāo)簽選擇器 類選擇器 屬性選擇器 繼承屬性: color,font,text-align,li...
    love2013閱讀 2,430評(píng)論 0 11
  • 畫畫課后我和兒子坐在回家的公交車上。 媽媽:“今天下午重新裝系統(tǒng)的那個(gè)手機(jī),對(duì)于你來說只是學(xué)習(xí)用的工具,里面...
    何金霖閱讀 241評(píng)論 0 0
  • 既然無法選擇開始 又何必不停地抱怨 不如用那些抱怨的時(shí)間 去呼喚 誰敢說冬天的呼喚 不是春天 既然無法選擇開始 又...
    淺得塾心靈文畫閱讀 191評(píng)論 2 7

友情鏈接更多精彩內(nèi)容