Web優化躬行記(1)——CSS

  Web優化的對象包括頁面性能、用戶體驗、開發效率、程式碼優化、網路延遲等,本系列會列舉出眾多常用的優化技巧,每個技巧都可深入分析,在此只做拋磚引玉。

  本系列優化內容提煉於《前端面試寶典》、《高效前端》、《高性能JavaScript》、《CSS重構》等書籍,以及《2020前端性能優化清單》等網路資源。

  CSS優化包括減少樣式量、合理使用CSS3特性、對樣式分類、採用預處理器等。

一、CSS選擇器

1)匹配優化

  由於CSS選擇器是從右往左進行匹配,因此下面的這條規則並不高效,瀏覽器需要遍歷頁面中的div元素並確定其父元素的id是否為「container」。

#container > div { }

  最右邊的參數叫關鍵選擇器,對瀏覽器執行的工作量起主要影響。在優化時,可將重心放到關鍵選擇器上。

2)保持簡潔

  雖然下面的選擇器非常精確,但是一旦HTML結構發生變化,匹配就會失敗。

div > nav > ul > li > a { }

  更佳的做法是為HTML元素增加一個類,並為該類增加樣式。簡潔的選擇器也會讓CSS文件變小。

.nav-link { }

3)語義化類名

  有意義的類名可提供恰如其分的樣式資訊,既能防止因細節過少而表意模糊,又能避免因資訊過多而妨礙程式碼重用,例如用「.animal」描述動物的樣式。

  注意,也不要過於精確,例如female-black-and-white-kitten(雌性—黑—和—白—小貓)。

4)避免相同類名

  有時候會故意寫相同類名,以覆蓋之前的樣式。但在多人協作時,很容易因為同名而發生衝突,可以引入一個命名空間加以區分。

5)偽類的妙用

  偽類不僅僅只是鏈接的懸浮、元素位置,CSS3新增了一大批偽類,既彌補了常規選擇器的不同,也能解決部分頁面交互。

  例如自定義單選框的選中樣式,以往得藉助JavaScript,現在只需幾句CSS就可完成。如下所示,為單選框聲明:checked偽類,

.ui-radio span {
  display: block;
  width: 100%;
  background: #FFF;
  color: #F60;
}
.ui-radio input[type=radio]:checked ~ span {
  background: #Fc0;
  color: #FFF;
}

二、CSS屬性

1)巧用繼承

  屬性繼承可以通過inherit關鍵字顯式聲明,而有些屬性還支援自動繼承,常用的包括:

  1. 字體系列屬性:font-family,font-size

  2. 文本系列屬性:text-indent,line-height,color

  3. 元素可見性:visibility

  4. 表格布局屬性:border-style

  5. 列表布局屬性:list-style,list-style-type

  6. 游標屬性:cursor

  布局相關的屬性大都不可繼承。樣式多繼承可以減少很多冗餘程式碼,減小CSS文件的大小,保持高可讀性,降低後期維護成本。

2)慎用!important

  聲明!important後的屬性,其特殊性非常高,很容易影響別處的樣式,並且在老舊項目中很難修改,會出現牽一髮動全身的情況。

3)flexbox

  彈性布局很適合移動端頁面,大大簡化了頁面布局難度,並且已經獲得了瀏覽器的廣泛支援。

  過去布局常會用float屬性,但其實它最初的作用是為了實現文字環繞影像的效果。當用於布局時,必須清除浮動,否則會造成父元素塌陷、非浮動元素環繞等問題。

  所以要避免使用float屬性,多用彈性布局。CSS3最新的網格布局比彈性布局更加強大,給出了許多優秀的布局解決方案。

4)屬性簡寫

  使用屬性簡寫,可以避免冗長的屬性聲明。當在大型樣式表中持續使用時,節省的空間將會很可觀。

.container {
  background-color: #FC0;
  background-image: url(lake.png);
  background-repeat: no-repeat;
  /* 簡寫 */
  background: #FC0 url(lake.png) no-repeat;
}

  還有一種簡寫,可用短的屬性描述相同的功能,例如當只需要聲明background-color屬性,可用background替代。

.container {
  background-color: #FC0;
  /* 簡寫 */
  background: #FC0;
}

4)減少冗餘

  將選擇器之間重複的屬性提取到一起,通過最小化屬性聲明的次數,來減少程式碼膨脹。

.main,
.side {
  margin: 20px;
  color: #F60;
}

5)偽元素

  偽元素可簡化頁面的HTML結構,例如可用它來畫那些無關緊要的分隔線,或用偽元素清除浮動、增加計數器等。

6)CSS3屬性

  CSS3提供了許多新屬性,可用來替換JavaScript或影像。

  例如CSS3的border-radius屬性和border-shadow屬性,可以不用再藉助影像實現圓角和陰影,不僅減少了與伺服器之間的通訊,還加快了開發速度。

  再例如CSS3提供了濾鏡(filter)功能,不必再藉助Canvas來實現濾鏡的功能。還有linear-gradient()函數用於繪製漸變

7)動畫

  很多動畫現在可以由CSS3屬性(animation和transition)實現,不必再藉助JavaScript,減少了JavaScript的權重。由於瀏覽器對CSS3的原生支援,因此動畫也變得更加流暢。

  animation常與transform結合,進行多層繪製,避免觸發影響渲染性能的重排和重繪。例如使用一個3D transform屬性將元素提升至合成層,進行GPU圖形處理加速。

.move {
  transform: translate3d(0,0,0);
}

8)will-change

  will-change屬性會告知瀏覽器該元素會有哪些變化,讓瀏覽器在元素屬性真正發生變化之前提前做好對應的優化準備工作。

  例如將一部分複雜的計算工作提前準備好,加快頁面反應速度。

三、程式碼組織

1)請求和位置

  用link元素載入CSS可實現並行請求,並且將CSS文件放置在head中儘早載入,防止無樣式的內容閃爍,加快初始頁面載入時的渲染速度。

2)減少base64

  有時候會將一些小圖標轉換成base64內嵌到CSS文件中,雖然這樣減少了通訊,但是會讓CSS文件極速膨脹,需要做適當地權衡。

3)內聯樣式

  如果CSS文件的內容很少,那麼可以直接將其內聯到HTML結構中。雖然對快取不利,但對首次載入有很大的作用。

4)殭屍程式碼

  殭屍程式碼是指存在但沒有使用的程式碼,需要將它們刪除。CSS中的殭屍程式碼具體表現為:沒有使用的聲明塊、重複的聲明塊和聲明語句。

5)分類

  按照樣式產生作用的順序組織CSS程式碼。

  1. 通用樣式,用來設定基準,以消除不同瀏覽器之間的不一致性。

  2. 基礎樣式,為網站的所有元素提供基本的樣式,例如留白(margin和padding)、字體、顏色等。

  3. 組件樣式,添加了樣式的元素或元素組合,例如進度條、彈框等。

  4. 結構化樣式,用來創建網頁的布局,常用於定義尺寸。

  5. 功能性樣式,所有樣式中最精確的樣式,為滿足單一目的而實現的樣式。

  6. 瀏覽器特定樣式,只對特定的瀏覽器生效,通常不夠優雅。

6)關鍵CSS

  關鍵CSS是用戶會立即看到的內容樣式(即首屏樣式),需要儘快載入。可將首屏樣式提取到單獨的文件中,或用工具將這些樣式內嵌到style元素中。

  對於首屏以外的樣式,可通過preload載入,使其不阻塞渲染,如下所示,使用as來指定將要預載入的內容類型。

<link rel="preload" href="style.css" as="style">

7)CSS預處理器

  CSS預處理器包括SASS和LESS,它們能為CSS提供了變數、函數、語句等編程特性,並引入了CSS模組化的功能。即使項目規模擴大,也能處理的遊刃有餘。

8)方法論

  CSS方法論是一種面向CSS、由個人和組織設計、已被諸多項目檢驗且公認有效的最佳實踐。

  這些方法論都會涉及結構化的命名約定,並且在組織CSS時可提供相應的指南,從而提升程式碼的性能、可讀性以及可維護性。

  目前比較流行的三種CSS方法論:OOCSS、BEM和SMACSS。