1. 程式人生 > >CSS重構:樣式表效能調優

CSS重構:樣式表效能調優

  這兩天窩在家裡又看了本CSS相關的書:《CSS重構:樣式表效能調優》。重構是指在不改變程式碼行為的前提下,重寫程式碼,使其更加簡潔、易於複用。

  這本書讀起來比較快,可挑自己感興趣的讀,前面三章是基礎知識的介紹,都瞭解的話可直接跳過。第四章是為樣式分類,我比較感興趣的是第四章(測試)和第五章(程式碼的組織和重構策略)。

一、測試

  測試時需要考慮很多因素,其中包括以下幾點:

1、正在用什麼瀏覽器測試網頁?

2、如何在不同的作業系統上測試各種各樣的瀏覽器?

3、正在多大的視窗瀏覽網頁?

4、如何快速測試大量網頁?

5、如何驗證你所看到的效果是正確的?

6、如果你無法獲得某些裝置,如何測試網站在這些裝置上的效果?

1)測試多個瀏覽器

  最常用的測試 CSS 在不同瀏覽器中顯示效果的方法是人工測試,主流瀏覽器包括Chrome、Firefox、Safari、Microsoft Edge等。

  為了測試 CSS 在移動端的效果,需要從合適的應用市場下載適合於裝置的各種瀏覽器。

1、要用iOS系統的Safari瀏覽器測試, 可以使用iOS原生裝置或Xcode的iOS模擬器。

2、安卓裝置可以用 Android Studio 的模擬器測試。

2)第三方測試服務

  除了自己測試,還可以使用第三方提供的種類豐富的測試服務。它們能夠滿足測試網站在任意瀏覽器或其他配置環境中的效果的需求,同時還提供類似共享測試階段資訊、人工測試多種瀏覽器和截圖等功能。

  下面列出的幾種第三方服務,有些可免費試用一段時間或提供幾種級別的免費服務:

1、BrowserStack

2、Sauce Labs

3、Browserling

4、Litmus

3)視覺迴歸測試

  視覺迴歸測試是一種測試方法,它通過比較作為基準的使用者介面影象和開發過程同一使用者介面的影象,來檢測不符合預期的改動(迴歸)。視覺迴歸測試非常耗時,因為需要測試的瀏覽器很多,一有改動就進行這種測試,測試工作量很大。此外,肉眼難以確定元素在空間位置上的變化。視覺迴歸測試有如下技巧:

1、測試重要的點,例如一旦基礎樣式定義好,就不大可能因為改動它們而引入錯誤;但是更為複雜、更加脆弱的可用性元件則是需要重點測試的。

2、保持足夠細緻的粒度,每次只測單個元件。

3、用多種瀏覽器進行視覺迴歸測試,因為不同瀏覽器之間可能存在不一致現象,即不要嘗試比較不同瀏覽器的截圖。

  Gemini專案是Yandex團隊開發的視覺迴歸測試工具。使用該工具,可以編寫指令碼,自動擷取網站在主流瀏覽器中的截圖,然後將其與基準影象比較,不同之處將以高亮形式標記出來。

  除了 Gemini, 還有多種視覺迴歸測試工具, 其中最常用的兩個是Wraith和PhantomCSS。前者由BBC開發,後者由Huddle公司的James Cryer帶領開發團隊編寫,它們能開啟網站,能用PhantomJS(基於WebKit的無頭瀏覽器)或 SlimerJS(基於Gecko的無頭瀏覽器)截圖,能對比網頁現有元素的截圖跟元素基準影象之間的差異。

二、維護程式碼

  程式碼的測試跟編寫同等重要。不斷維護已有程式碼,提高其質量,其重要性不亞於編寫新程式碼。

1)編碼規範

  編碼規範是指將良好的程式碼編寫方法記錄下來形成指南,以鼓勵團隊所有成員以相同的方式編寫程式碼。CSS 編碼規範通常指定了註釋、格式、命名和選擇器用法方面的規範,其詳略程度可根據實際情況自行調整。

  (1)註釋

  A. 應該在每個檔案的開頭添加註釋,說明檔案的內容。

/** 
* 該檔案包含選項卡組的樣式。 
* 選項卡組應僅包含擁有tab類的元素。
*/

  B. 易於混淆的屬性,應用註釋予以說明。

.tab-group-flush {
  display: block;
  margin-left: -12px; /* 清除父容器的padding值 */
  margin-right: -12px; /* 清除父容器的padding值 */
}

  (2)格式

  A. 規則集應該滿足下列要求。

1、有多個屬性時,每個屬性佔一行。

2、規則集宣告塊中的每條宣告縮排 4 個空格。

.selector { 
    property1: value;
    property2: value;
}

  B. 宣告語句應該滿足下列要求。

1、冒號後面加1個空格。

2、必須以分號結尾。

.selector {
    property1: value;
}

  C. background-position各個屬性值不同時,可以將兩個屬性值放在一行。

.selector1 { background-position: 0 0; }
.selector2 { background-position: 0 -10px; }
.selector3 { background-position: 0 -10px; }

  D. 規則集和宣告末尾的空格必須刪除。

  (3)選擇器命名規範

  A. 只允許使用小寫字母。

.selector {}

  B. 包含多個單詞的選擇器必須使用脊柱狀形式(用連字元連線單詞)。

.selector-with-multiple-words {}

  C. 禁止用ID為元素新增樣式,應該使用類。

.element-to-style {}

  D. 用JavaScript修改樣式(不管用什麼框架),都必須通過增加或刪除CSS類來完成。

/**
* 正確:用 JavaScript 為元素新增類,修改元素的樣式。
*/ 
$(".js-menu-item").on("click", function(e) {
  $(this).addClass("highlighted");
});

  E. 用作 JavaScript 選擇器的類和 ID ,必須新增 js- 字首,並嚴禁在樣式表中使用。

/**
* 正確:在JavaScript中,用專門用作JavaScript選擇器的類選擇元素。
*/
$(".js-menu-item").on("click", function() {
  $(this).addClass("highlighted");
});

  F. 必須使用有意義的類名。

/* 正確:類的命名有意義且描述清楚。 */ 
.resident {}

  G. 類名必須描述為什麼元素新增樣式,而不是怎樣新增樣式。

/* 正確:類的命名描述的是為什麼元素新增樣式。 */ 
.sidebar-important {}

  (4)屬性

  A. 屬性的簡寫形式只可用於border、margin和padding。

/* 正確:僅border屬性使用了簡寫形式。 */ 
.selector {
    border: 1px solid #000000;
    font-family: Arial, sans-serif;
    font-size: 12px;
}

  B. 屬性必須按照字母順序排列。

.selector {
    border: 1px solid #000000;
    margin: 24px;
    padding: 12px;
}

  C. 屬性值為0時,必須省略單位。

.selector {
    border: 1px solid #000000;
    margin: 0;
    padding: 0;
}

  更多編碼規範方面的啟示,請見下面這些規範:

1、Google CSS編碼規範

2、18F前端指南

2)模式庫

  模式庫 (有時也稱樣式指南)是網站使用的一組使用者介面模式,它展示了每種模式相關的重要資訊,其中包括以下幾點:

1、何時(不)使用模式的指導。

2、解釋模式使用方式的示例程式碼。

3、使用某一模式而不用另一模式的原因。

  模式庫有如下幾個優點。

1、首先,模式庫將網站所有元件彙集到一起。參與專案的所有成員都能瞭解到搭建網站的各個模組,確保他們熟悉其背後的原理。讓每個人都熟悉一組可複用的模式,還能加快開發速度,因為開發新專案時,無需從頭重新開發這些構建模組。

2、模式庫將所有元件彙集到一起,還有助於保證使用者介面的一致性。使用模式庫對設計團隊也能起到幫助作用,因為需要修改元件的樣式時,在現有模式的基礎上做修改即可。模式庫為設計工作提供約束條件,鼓勵設計師在現有模式的基礎上設計新的元素,這進一步強化了使用者介面應該保持一致的設計理念。

3、最後,模式庫將網站的所有元件都彙集到一起,使識別不一致的元件變得更加容易。編寫的新程式碼可能影響到使用者介面效果,在提交程式碼之前,藉助模式庫,可從視覺上快速識別錯誤。修改模式後,若網頁看起來有問題,有了模式庫,診斷問題將更加容易,因為模式庫是模式的最簡單應用形式。

  Yelp和MailChimp的模式庫在各個方面都做得非常出色。關於模式庫的更多資源,請見styleguides.io, 該網站提供相關示例、文章、圖書和播客。

三、程式碼的組織和重構策略

1)按照樣式從最不精確到最精確組織 CSS

  CSS 樣式根據選擇器的特指度和樣式的順序產生作用。因此,有必要按照樣式產生作用的順序組織 CSS 程式碼。

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

2、基礎樣式,為網站的所有元素提供基本的樣式。留白( margin、padding和line-height等)、字型及其大小等樣式。

3、元件及其容器的樣式,滿足網站範圍內的大多數應用場景,樣式上的任何調整都應該交由父容器處理。

4、結構化樣式,包括元件及其容器的樣式。 該類樣式用來建立網頁的佈局,並常用於定義尺寸。

5、功能性樣式,所有樣式中最精確的樣式。 JavaScript所使用的新增 !important 語句的類就屬於這類樣式,其他為滿足單一目的而實現的樣式也屬於該類。

6、瀏覽器特定樣式(如果一定需要),只對特定的瀏覽器生效。通常不夠優雅,因此不再使用時,一定要將其刪除。

  按照以上順序新增 CSS, 隨著宣告塊選擇器的精確度提高,更為複雜的選擇器將與已經新增的更加寬泛的選擇器區分開來。

2)多個檔案還是一個大檔案

  程式碼的組織方式有兩種,即將程式碼置於多個檔案或只用一個大檔案。程式碼放置位置要易於開發人員查詢,這一點很重要,並且同樣非常重要的是,這樣做有助於網站快速載入以滿足終端使用者的需要。

1、儘可能地使需要下載的 CSS 檔案縮小,以便提高載入速度。

2、小型專案用一個 CSS 檔案完全可以接受,合理地將 CSS 檔案內容劃分為幾個大塊,每個大塊下再恰當安排小塊內容,併合理添加註釋。

/**
 * 通用樣式
 * ---------------------------------------------
 */

/**
 * 基礎樣式
 * ---------------------------------------------
 */
/* 基礎樣式:表單 */ 
/* 基礎樣式:標題 */ 
/* 基礎樣式:影象 */

3、開發網站時使用多個 CSS 檔案,各個檔案所包含的樣式可以分別服務於網站的某一部分功能,從而可以避免將 CSS 新增到不恰當的位置。

|-css/ | 
|-normalizing-styles | 
| |- normalize.css | 
| | 
|-base-styles | 
| |- forms.css | 
| |- headings.css | 
| |- images.css | 
| |- lists.css | 
| |- tables.css | 
| |- etc. | 
| | 
|-component-styles | 
| |- alerts.css | 
| |- buttons.css | 
| |- carousel.css | 
| |- dropdowns.css | 
| |- modals.css | 
| |- etc. | 
| | 
|- structural-styles | 
| |- layout-checkout.css | 
| |- layout-sidebar.css | 
| |- layout-primary.css | 
| |- layout-settings.css | 
| |- etc. | 
| | 
|- utility-styles | 
| |- utility.css | 
| | 
|- browser-specific-styles | 
| |-ie8.css

3)重構前審查CSS

  從以下更高的角度來審查 CSS,將非常有助於重構:

1、所用到的屬性列表

2、使用某一特定屬性的宣告塊列表

3、使用的顏色數量

4、使用的最高和最低特指度

5、擁有最高和最低特指度的選擇器

6、選擇器的長度

  CSS Dig是 Google Chrome 瀏覽器的一款免費外掛, 你可以用它獲取到以上資訊。

4)重構策略

  條件允許的話, 應該只對你能夠維護的小塊程式碼進行重構,並做到經常評審和釋出。

  1、保持規則集結構的一致性可以使開發更容易。請確定好宣告塊的格式和宣告語句的順序。 每條宣告語句可以各佔一行,並儘可能按照字母順序排列。

  2、刪除殭屍程式碼,殭屍程式碼是指存在但沒有使用的程式碼,包括沒有使用的宣告塊、重複的宣告塊和宣告語句。

  3、分離CSS和JavaScript,搜尋JavaScript程式碼, 找到選取元素的位置, 然後在選擇器前面新增 js- ,同時將該選擇器新增到HTML程式碼中定義該元素的位置。

  4、分離基礎樣式,將基礎樣式分為以下不同類別:

  • 標題(<h1>–<h6>)
  • 文字(例如:<p>、<span>和<code>)
  • 超連結(<a>)
  • 列表(<dl>、<ol>和<ul>)
  • 表格(例如:<table>、<thead>、<tbody>、<tfoot>、<tr>和<td>)
  • 表單(例如:<form>、<legend>、<fieldset>、<input>和<button>)
  • 媒體(例如:<audio>、<object>和<video>)

  分完類之後,你可以用 CSS Dig尋找某一特定類別的選擇器。找到選擇器的使用頻率和使用位置之後,你可以對它們進行比較,看看哪個屬性更常用。如果一個型別選擇器單獨使用,且只用過一次,就可以放心將其刪除。然而,如果一個型別選擇器用過多次,請按以下步驟重構。

  • 對於樣式要予以重構的型別選擇器,在基礎樣式中新建一條規則集。

  • 從所有用到該型別選擇器的地方找到最常用的屬性,將其新增到新規則集中。

  • 從其他規則集刪除重複的屬性,因為它們可以繼承新定義的基礎樣式。

  5、刪除冗餘的ID,對擁有多個 ID 的選擇器進行重構時,首先可以將最右側 ID 左邊的一切統統刪除。因為同一個ID在一個網頁最多隻能使用一次,一個選擇器包含多個 ID 實屬冗餘。

  6、將ID轉化為類,該過程雖然要花費一定時間,但是最終得到的 CSS 特指度更低、更易於複用。將 ID 改為類時,請記得使用意義明確的類名,切記不要使用晦澀或過於精確的名稱。如果解決某一特定問題需要改動大量的選擇器,那麼最好不要將 ID 轉化為類,而是等將更精確樣式選擇器的特指度降低之後,再來重構這部分程式碼。

  7、區分功能性樣式,功能性樣式是唯一應該使用 !important 宣告的樣式。若不得不使用 !important 的樣式,且用途單一(如隱藏元素),應將其作為功能樣式寫到樣式表的同一地方。在拼接 CSS 時功能樣式應該置於 CSS 檔案的底部,因此整合 CSS 檔案時,一定要恰當安排功能性樣式的位置。

  8、定義可複用元件,可以從經常重複使用的介面模式(例如:選項卡)著手,花點時間調研網站什麼地方用到了該模式。 請記錄該模式的各種變體, 並判斷它們是合乎規範的, 還是由於不一致的CSS 而導致的。

  9、刪除行內CSS和過於模組化的類,兩種行為應該同時進行, 因為它們在本質上是相同的, 只不過用 style 屬性新增的行內 CSS 其特指度更高,除非用 !important 宣告覆蓋了行內樣式。刪除行內CSS和過於模組化的類(每個類應用一種樣式,它們總是需要一起使用,如下程式碼所示)都應該晚些重構。

<h1 class="font-bold uppercase blue-text margin-bottom-large no-padding">
   Too Many CSS Classes 
</h1>

  10、隔離面向特定瀏覽器的CSS樣式,這些程式碼很容易汙染其他 CSS, 因此我們需要對其進行區分。但是在隔離之前, 請記得檢視網站的流量來源,以判斷是否能夠放棄支援這些瀏覽器。

5)評估重構是否成功

  下面是重構完成之後如何評價是否成功的一些想法。 其中一些建議,比如檢查檔案的大小,在重構之前也應要做,以便與重構之後進行比較。

  1、你的網站崩潰了嗎?

  判斷程式碼重構之後成功與否的首要的、最明顯的方式是確認網站的行為是否倒退。如果經過徹底的視覺效果檢測之後沒有發現視覺效果方面的問題,那麼接下來你需要考慮其他方面。

  • 低耦合度,通過建立可複用元件和用容器包裹元件,你可以實現 CSS 和 HTML 的分離。雖然一定程度的耦合度一直存在,但是還是要避免使用過於複雜的選擇器。
  • 低特指度,選擇器的特指度指標可用於度量程式碼庫的特指度,以判斷程式碼庫是否包含大量高特指度的選擇器,這些選擇器將增加程式碼的維護成本。
  • 更少的檔案數量和更小的檔案,拼接可以減少需要下載的檔案數量,壓縮可以刪除多餘字元以減小檔案體積。

  2、UI Bug數

  一旦你開始重構 CSS 並遵循編碼標準,因程式碼凌亂或程式碼重複而引入的 UI bug 數量應該會減少。軟體 bug 是不可避免的(網站開發人員可能引入 bug, 瀏覽器廠商可能引入瀏覽器問題),但是使用模式庫和執行視覺效果測試百試不爽,它們能夠幫你更快地檢測和診斷這些問題。

  3、減少開發和測試時間

  將 CSS 以符合邏輯的方式分成多個檔案,確立了編碼標準,並建立了使用者介面模式庫之後,應該能夠較以往更快地構建和維護使用者介面了。除了降低開發時間,如果你能熟練使用正確的工具,你也許還注意到你可以更快地測試介面。

&n