CSS 預處理器是什麼?一般來說,它們基於CSS 擴展了一套屬於自己的DSL(Domain Specific Language),來解決我們書寫CSS 時難以解決的問題:
歸結起來就是抽象能力。所以這決定了 CSS 預處理器的主要目標:提供 CSS 缺少的樣式層重複使用機制、減少冗餘程式碼,提高樣式程式碼的可維護性。這不是錦上添花,而恰恰是雪中送炭。
但是,CSS 預處理器也不是萬金油,CSS 的好處是簡單、隨時隨地被使用和調試。預編譯 CSS 步驟的加入,讓我們開發工作流程多了一個環節,除錯也變得更麻煩了。更大的問題在於,預編譯很容易造成後代選擇器的濫用。所以在使用 CSS 預處理器時,要注意避免此類問題。
Sass 中變數以 $ 打頭比較不容易和 CSS 標準語法衝突。 Less 中變數則以 @ 打頭,雖說容易和後續規範更新的新語法衝突,但是理論上只要 CSS 規範不引入 @a: b
這樣的規則,問題也不大。而且規範制定的時候也會參考很多現有的實作。
Sass 和Less 的變數機制有很大的不同,Sass 是類似JS 的區塊級作用域一樣,可以在作用域內重新賦值而不影響外部,Less 是以全域的最後一次賦值為準。 SASS 和 SCSS 只是兩種文法風格而已,SCSS 比較貼近 CSS 文法,前端寫起來比較舒服。 Less 和 Sass 最常用的部分並沒有明顯的區別,不用太在意該用哪一個,Just pick one。至於公司用哪個,跟著用就行,不出大問題不用考慮換。
頁面越來越複雜,需要載入的CSS 檔案也越來越大,我們有必要把大檔案切分開來,否則難以維護。傳統的 CSS 文件切分方案基本上就是 CSS 原生的 @import
指令,或在 HTML 中載入多個 CSS 文件,這些方案通常無法滿足效能需求。
CSS 預處理器擴展了 @import
指令的能力,透過編譯環節將切分後的檔案重新合併為一個大檔案。這一方面解決了大檔案不便維護的問題,另一方面也解決了一堆小檔案在載入時的效能問題。
把檔案切分的想法再往前推進一步,就是「模組化」。一個大的 CSS 檔案在合理切分之後,所產生的這些小檔案的相互關係應該是一個樹狀結構。
樹形的根結節一般稱為“入口文件”,樹形的其它節點一般稱為“模組文件”。入口文件通常會依賴多個模組文件,各個模組文件也可能依賴其它更末端的模組,從而構成整個樹形。
以下是一個簡單的範例:
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 是 CSS 预处理器提供的又一项实用功能。Mixin 的形态和用法跟函数十分类似——先定义,然后在需要的地方调用,在调用时可以接受参数。它与函数的不同之处在于,函数用于产生一个值,而 Mixin 的作用是产生一段 CSS 代码。
Mixin 可以产生多条 CSS 规则,也可以只产生一些 CSS 声明。
一般来说,Mixin 可以把 CSS 文件中类似的代码块抽象出来,并给它一个直观的名字。比如 CSS 框架可以把一些常用的代码片断包装为 mixin 备用,在内部按需调用,或暴露给使用者在业务层调用。
举个例子,我们经常会用到 clearfix 来闭合浮动。在原生 CSS 中,如果要避免 clearfix 代码的重复,往往只能先定义好一个 .clearfix
类,然后在 HTML 中挂载到需要的元素身上:
/* 为 clearfix 定义一个类 */ .clearfix {...} .clearfix::after {...}复制代码
<!-- 挂载到这两个元素身上 --><p class="info clearfix">...</p>...<footer class="clearfix">...</footer>复制代码
把表现层的实现暴露到了结构层,是不是很不爽?而在预处理器中,我们还可以选择另一种重用方式:
// 为 clearfix 定义一个 mixin clearfix() ... &::after ... // 在需要的元素身上调用 .info clearfix() footer clearfix()复制代码
CSS 预处理语言无法直接运行于浏览器环境,这意味着我们编写的源码需要编译为 CSS 代码之后才能用于网页。这似乎是一个门槛,需要我们付出“额外”的成本。
但在目前的大环境下,大多数项目的前端开发流程已经包含了构建环节,比如选择任何一个脚本模块化方案都是需要在部署时走一道打包程序的。所以对大多数团队来说,这个门槛其实已经跨过去一大半了。
而一旦接受了这种设定,我们还可以享受到“额外”的福利。在给 CSS 的开发加入编译环节的同时,还可以顺道加入其它构建环节,比如代码校验、代码压缩、代码后处理等等。
“代码后处理”是指 PostCSS 平台上各类插件所提供的功能,光是 Autoprefixer 这一项就已经值回票价了。我们再也不需要在 CSS 代码中手工添加浏览器前缀了,直接使用标准写法,剩下的事情让工具搞定吧!
推荐教程:《CSS教程》
以上是CSS 預處理器的詳細內容。更多資訊請關注PHP中文網其他相關文章!