初談 CSS 預處理器

CSS 預處理器是什麼?通常來講,它們基於 CSS 擴展了一套屬於本身的 DSL(Domain Specific Language),來解決咱們書寫 CSS 時難以解決的問題:css

  • 語法不夠強大,好比沒法嵌套書寫致使模塊化開發中須要書寫不少重複的選擇器;
  • 沒有變量和合理的樣式複用機制,使得邏輯上相關的屬性值必須以字面量的形式重複輸出,致使難以維護。

歸結起來就是抽象能力。因此這就決定了 CSS 預處理器的主要目標:提供 CSS 缺失的樣式層複用機制、減小冗餘代碼,提升樣式代碼的可維護性。這不是錦上添花,而偏偏是雪中送炭。html

可是,CSS 預處理器也不是萬金油,CSS 的好處在於簡便、隨時隨地被使用和調試。預編譯 CSS 步驟的加入,讓咱們開發工做流中多了一個環節,調試也變得更麻煩了。更大的問題在於,預編譯很容易形成後代選擇器的濫用。因此在使用 CSS 預處理器時,要注意避免出現此類問題。前端

Sass 中變量以 $ 打頭比較不容易和 CSS 標準語法衝突。Less 中變量則以 @ 打頭,雖然說容易和後續規範更新的新語法衝突,可是理論上只要 CSS 規範不引入 @a: b 這樣的規則,問題也不大。並且規範制定的時候也會參考不少現有的實現。git

Sass 和 Less 的變量機制有很大的不一樣,Sass 是相似 JS 的塊級做用域同樣,能夠在做用域內從新賦值而不影響外部,Less 是以全局的最後一次賦值爲準。SASS 和 SCSS 只是兩種語法風格而已,SCSS 更貼近 CSS 語法,前端寫起來更舒服。Less 和 Sass 最經常使用的部分並無明顯的區別,不用太在乎該用哪一個,Just pick one。至於公司用哪一個,跟着用就行,不出大問題不用考慮換。github

CSS 預處理器能夠爲咱們提供如下「超能力」

下文複製自 淺談 CSS 預處理器(一):爲何要使用預處理器?,文中的示例代碼均採用 Stylus 做爲 CSS 預處理語言。編程

文件切分

頁面愈來愈複雜,須要加載的 CSS 文件也愈來愈大,咱們有必要把大文件切分開來,不然難以維護。傳統的 CSS 文件切分方案基本上就是 CSS 原生的 @import 指令,或在 HTML 中加載多個 CSS 文件,這些方案一般不能知足性能要求。瀏覽器

CSS 預處理器擴展了 @import 指令的能力,經過編譯環節將切分後的文件從新合併爲一個大文件。這一方面解決了大文件不便維護的問題,另外一方面也解決了一堆小文件在加載時的性能問題。bash

模塊化

把文件切分的思路再向前推動一步,就是「模塊化」。一個大的 CSS 文件在合理切分以後,所產生的這些小文件的相互關係應該是一個樹形結構。app

樹形的根結節通常稱做「入口文件」,樹形的其它節點通常稱做「模塊文件」。入口文件一般會依賴多個模塊文件,各個模塊文件也可能會依賴其它更末端的模塊,從而構成整個樹形。框架

如下是一個簡單的示例:

entry.less
 ├─ base.less
 │   ├─ normalize.less
 │   └─ reset.less
 ├─ layout.less
 │   ├─ header.less
 │   │   └─ nav.less
 │   └─ footer.less
 ├─ section-foo.less
 ├─ section-bar.less
 └─ ...
複製代碼

入口文件 entry.less 在編譯時會引入所需的模塊,生成 entry.css,而後被頁面引用。

若是你用過其它擁有模塊機制的編程語言,應該已經深有體會,模塊化是一種很是好的代碼組織方式,是開發者設計代碼結構的重要手段。模塊能夠很清晰地實現代碼的分層、複用和依賴管理,讓 CSS 的開發過程也能享受到現代程序開發的便利。

選擇器嵌套

選擇符嵌套是文件內部的代碼組織方式,它可讓一系列相關的規則呈現出層級關係。

變量

在變動出現以前,CSS 中的全部屬性值都是「幻數」。你不知道這個值是怎麼來的、它的什麼樣的意義。有了變量以後,咱們就能夠給這些「幻數」起個名字了,便於記憶、閱讀和理解。

接下來咱們會發現,當某個特定的值在多處用到時,變量就是一種簡單而有效的抽象方式,能夠把這種重複消滅掉,讓你的代碼更加 DRY。

變量讓開發者更容易實現網站視覺風格的統一,也讓「換膚」這樣的需求變得更加輕鬆易行。

運算

光有變量仍是不夠的,咱們還須要有運算。若是說變量讓值有了意義,那麼運算則可讓值和值創建關聯。有些屬性的值其實跟其它屬性的值是緊密相關的,CSS 語法沒法表達這層關係;而在預處理語言中,咱們能夠用變量和表達式來呈現這種關係。

舉個例子,咱們須要讓一個容器最多隻顯示三行文字,在之前咱們一般是這樣寫的:

.wrapper {
	overflow-y: hidden;
	line-height: 1.5;
	max-height: 4.5em;  /* = 1.5 x 3 */
}
複製代碼

你們能夠發現,咱們只能用註釋來表達 max-height 的值是怎麼來的,並且註釋中 3 這樣的值也是幻數,還須要進一步解釋。將來當行高或行數發生變化的時候,max-height 的值和註釋中的算式也須要同步更新,維護起來很不方便。

接下來咱們用預處理語言來改良一下:

.wrapper
	$max-lines = 3
	$line-height = 1.5

	overflow-y: hidden
	line-height: $line-height
	max-height: unit($line-height * $max-lines, 'em')
複製代碼

乍一看,代碼行數彷佛變多了,但代碼的意圖卻更加清楚了——不須要任何註釋就把整件事情說清楚了。在後期維護時,只要修改那兩個變量就能夠了。

值得一提的是,這種寫法還帶來另外一個好處。$line-height 這個變量能夠是 .wrapper 本身定義的局部變量(好比上面那段代碼),也能夠從更上層的做用域獲取:

$line-height = 1.5  // 全局統一行高

body
	line-height: $line-height

.wrapper
	$max-lines = 3

	max-height: unit($line-height * $max-lines, 'em')
	overflow-y: hidden
複製代碼

這意味着 .wrapper 能夠向祖先繼承行高,而不須要爲這個「只顯示三行」的需求把本身的行高寫死。有了運算,咱們就有能力表達屬性與屬性之間的關聯,它令咱們的代碼更加靈活、更加 DRY。

函數

把經常使用的運算操做抽象出來,咱們就獲得了函數。

開發者能夠自定義函數,預處理器本身也內置了大量的函數。最經常使用的內置函數應該就是顏色的運算函數了吧!有了它們,咱們甚至都不須要打開 Photoshop 來調色,就能夠獲得某個顏色的同色系變種了。

舉個例子,咱們要給一個按鈕添加鼠標懸停效果,而最簡單的懸停效果就是讓按鈕的顏色加深一些。咱們寫出的 CSS 代碼多是這樣的:

.button {
	background-color: #ff4466;
}
.button:hover {
	background-color: #f57900;
}
複製代碼

我相信即便是最資深的視覺設計師,也很難分清 #ff4466#f57900 這兩種顏色到底有什麼關聯。而若是咱們的代碼是用預處理語言來寫的,那事情就直觀多了:

.button
	$color = #ff9833

	background-color: $color
	&:hover
		background-color: darken($color, 20%)
複製代碼

此外,預處理器的函數每每還支持默認參數、具名實參、arguments 對象等高級功能,內部還能夠設置條件分支,能夠知足複雜的邏輯需求。

Mixin

Mixin 是 CSS 預處理器提供的又一項實用功能。Mixin 的形態和用法跟函數十分相似——先定義,而後在須要的地方調用,在調用時能夠接受參數。它與函數的不一樣之處在於,函數用於產生一個值,而 Mixin 的做用是產生一段 CSS 代碼。

Mixin 能夠產生多條 CSS 規則,也能夠只產生一些 CSS 聲明。

通常來講,Mixin 能夠把 CSS 文件中相似的代碼塊抽象出來,並給它一個直觀的名字。好比 CSS 框架能夠把一些經常使用的代碼片段包裝爲 mixin 備用,在內部按需調用,或暴露給使用者在業務層調用。

舉個例子,咱們常常會用到 clearfix 來閉合浮動。在原生 CSS 中,若是要避免 clearfix 代碼的重複,每每只能先定義好一個 .clearfix 類,而後在 HTML 中掛載到須要的元素身上:

/* 爲 clearfix 定義一個類 */
.clearfix {...}
.clearfix::after {...}
複製代碼
<!-- 掛載到這兩個元素身上 -->
<div class="info clearfix">...</div>
...
<footer class="clearfix">...</footer>
複製代碼

把表現層的實現暴露到告終構層,是否是很不爽?而在預處理器中,咱們還能夠選擇另外一種重用方式:

// 爲 clearfix 定義一個 mixin
clearfix()
    ...
    &::after
        ...

// 在須要的元素身上調用
.info
    clearfix()

footer
    clearfix()
複製代碼

工程化

CSS 預處理語言沒法直接運行於瀏覽器環境,這意味着咱們編寫的源碼須要編譯爲 CSS 代碼以後才能用於網頁。這彷佛是一個門檻,須要咱們付出「額外」的成本。

但在目前的大環境下,大多數項目的前端開發流程已經包含了構建環節,好比選擇任何一個腳本模塊化方案都是須要在部署時走一道打包程序的。因此對大多數團隊來講,這個門檻其實已經跨過去一大半了。

而一旦接受了這種設定,咱們還能夠享受到「額外」的福利。在給 CSS 的開發加入編譯環節的同時,還能夠順道加入其它構建環節,好比代碼校驗、代碼壓縮、代碼後處理等等。

「代碼後處理」是指 PostCSS 平臺上各種插件所提供的功能,光是 Autoprefixer 這一項就已經值回票價了。咱們不再須要在 CSS 代碼中手工添加瀏覽器前綴了,直接使用標準寫法,剩下的事情讓工具搞定吧!

參考資料

本文中大部份內容直接複製整合了參考資料中的內容,由於這些文章寫的很好,不必再用本身的話複述,所以取長補短,進行了整合,版權歸原做者全部。

相關文章
相關標籤/搜索