這兩天窩在家里又看了本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)第三方測試服務
除了自己測試,還可以使用第三方提供的種類豐富的測試服務。它們能夠滿足測試網站在任意瀏覽器或其他配置環境中的效果的需求,同時還提供類似共享測試階段信息、人工測試多種瀏覽器和截圖等功能。
下面列出的幾種第三方服務,有些可免費試用一段時間或提供幾種級別的免費服務:
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; }
更多編碼規范方面的啟示,請見下面這些規范:
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 以符合邏輯的方式分成多個文件,確立了編碼標准,並創建了用戶界面模式庫之后,應該能夠較以往更快地構建和維護用戶界面了。除了降低開發時間,如果你能熟練使用正確的工具,你也許還注意到你可以更快地測試界面。