詳細(xì)解讀CSS的預(yù)編譯器PostCSS

提到css預(yù)編譯器(css preprocessor),你可能想到Sass、Less以及Stylus。而本文要介紹的PostCSS,正是一個(gè)這樣的工具:css預(yù)編譯器可以做到的事,它同樣可以做到。
“你說的我都懂,那為什么要用它?”
套裝與單件
如果Sass等預(yù)編譯器是新定義了一種模板語言,然后將其轉(zhuǎn)化為css的話,PostCSS則是更純粹地對(duì)css本身做轉(zhuǎn)換。
回想一下你是如何學(xué)習(xí)使用css預(yù)編譯器的:了解到有這樣一種可以轉(zhuǎn)化為css的語言,它有很多特性,變量、嵌套、繼承等等,每一種特性都通過一定語法實(shí)現(xiàn)。大概就像是遞給你一個(gè)已經(jīng)封裝好的工具箱(量產(chǎn)型?),你可以在里面找有用的東西。
那PostCSS是怎樣呢?PostCSS就像只遞給你一個(gè)盒子,但告訴你你可以從旁邊的陳列柜取走自己想要的工具放進(jìn)盒子打包帶走。如果你覺得陳列柜里的不夠好,PostCSS還可以幫你打造你自己的工具。所以,使用PostCSS,你可以僅取所需。
這就是PostCSS的模塊化(modular)風(fēng)格。它作為一個(gè)css轉(zhuǎn)換工具,自身很小,其所有的轉(zhuǎn)換功能都是插件,因此可以個(gè)性化配置。
PostCSS的簡(jiǎn)要原理
PostCSS自身只包括css分析器,css節(jié)點(diǎn)樹API,source map生成器以及css節(jié)點(diǎn)樹拼接器。
css的組成單元是一條一條的樣式規(guī)則(rule),每一條樣式規(guī)則又包含一個(gè)或多個(gè)屬性&值的定義。所以,PostCSS的執(zhí)行過程是,先css分析器讀取css字符內(nèi)容,得到一個(gè)完整的節(jié)點(diǎn)樹,接下來,對(duì)該節(jié)點(diǎn)樹進(jìn)行一系列轉(zhuǎn)換操作(基于節(jié)點(diǎn)樹API的插件),最后,由css節(jié)點(diǎn)樹拼接器將轉(zhuǎn)換后的節(jié)點(diǎn)樹重新組成css字符。期間可生成source map表明轉(zhuǎn)換前后的字符對(duì)應(yīng)關(guān)系:
比較有意思的是,PostCSS的插件其實(shí)都是JavaScript函數(shù),它們使用PostCSS的節(jié)點(diǎn)樹API,對(duì)css節(jié)點(diǎn)樹進(jìn)行不同的轉(zhuǎn)換。
插件預(yù)覽
所有插件都可以在PostCSS的主頁中查詢到,這里只選取一小部分示意一下。
Autoprefixer
PostCSS最有名的插件是Autoprefixer。如名所示,可以自動(dòng)為你添加瀏覽器私有前綴。它的添加值會(huì)參考Can I Use及你設(shè)定的瀏覽器支持范圍,因此相當(dāng)可靠。下面是一個(gè)示例(以我設(shè)定的瀏覽器支持范圍):
- .container{
- display: flex;
- }
編譯后:
- .container{
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- }
postcss-nested&postcss-mixins
在剛開始使用PostCSS時(shí),我就想到要用PostCSS實(shí)現(xiàn)我在Sass中最常用的特性。所以,我找到了postcss-nested和postcss-mixins。將它們結(jié)合起來后,就可以做到這樣:
- @define-mixin clearfix{
- &:after{
- display: table;
- clear: both;
- content: " ";
- }
- }
- .column-container{
- color: #333;
- @mixin clearfix;
- }
編譯后:
- .column-container{
- color: #333;
- }
- .column-container:after{
- display: table;
- clear: both;
- content: " ";
- }
到這里,你是否已經(jīng)有了“預(yù)編譯器可以做到的它也可以做到”的感覺呢?
如何使用PostCSS
我個(gè)人推薦結(jié)合Gulp使用,本文在此只介紹gulp-postcss的用法。
gulp-postcss及插件都是npm,首先,使用npm install將它們分別安裝到項(xiàng)目目錄中(會(huì)位于node_modules)。然后,編輯glupfile.js,將PostCSS注冊(cè)為Gulp的一個(gè)任務(wù)。以下是一個(gè)結(jié)合使用了Autoprefixer、postcss-simple-vars、postcss-mixins、postcss-nested4個(gè)插件,且生成source map文件的例子:
- var gulp = require("gulp");
- var postcss = require("gulp-postcss");
- var autoprefixer = require('autoprefixer-core');
- var postcssSimpleVars = require("postcss-simple-vars");
- var postcssMixins = require("postcss-mixins");
- var postcssNested = require("postcss-nested");
- var sourcemaps = require("gulp-sourcemaps");
- // Css process.
- gulp.task("postcss", function(){
- var processors = [
- postcssMixins,
- postcssSimpleVars,
- postcssNested,
- autoprefixer({
- browsers: ["Android 4.1", "iOS 7.1", "Chrome > 31", "ff > 31", "ie >= 10"]
- })];
- return gulp.src(["./stylesheets/src/*.css"])
- .pipe(sourcemaps.init())
- .pipe(postcss(processors))
- .pipe(sourcemaps.write("."))
- .pipe(gulp.dest("./stylesheets/dest"));
- });
在上面這段代碼中,processors是一個(gè)數(shù)組,定義了用到的PostCSS插件。PostCSS會(huì)按照定義順序依次執(zhí)行插件,因此,在結(jié)合多個(gè)插件使用時(shí),請(qǐng)注意它們的位置。
自定義轉(zhuǎn)換
此外,你可以很容易地創(chuàng)建你自己的轉(zhuǎn)換(還記得前面說過PostCSS的插件都是JavaScript函數(shù)吧?)。例如,下面是一個(gè)自定義的轉(zhuǎn)換方法,它將css代碼中的帶有rem單位的值,更改為px的值。
- var custom = function(css, opts){
- css.eachDecl(function(decl){
- decl.value = decl.value.replace(/\d+rem/, function(str){
- return 16 * parseFloat(str) + "px";
- });
- });
- };
然后,你將這個(gè)方法直接添加到processors中(就像postcssMixins那些那樣)就可以使用。如果原來有值是3rem,將變成48px。
以上只是一個(gè)簡(jiǎn)單的轉(zhuǎn)換,如果要正式做一個(gè)插件,請(qǐng)參考PostCSS插件指南。
性能
PostCSS宣稱,由JavaScript編寫的PostCSS比C++編寫的libsass(Sass原本是Ruby編寫的,但后來出了C++的引擎,也就是libsass,它更快)還要快3倍。這里的具體數(shù)字我覺得不用多關(guān)心,可以感受到“PostCSS的運(yùn)行速度很快”就足夠了。
實(shí)際運(yùn)行起來大概這樣:
做到更多
基于PostCSS,可以做到許多現(xiàn)有的css預(yù)編譯器做不到的事。例如,插件系列cssnext可以讓你使用CSS4+的語法(增加了變量等許多特性),它會(huì)幫你轉(zhuǎn)化為目前可用的CSS3。
一點(diǎn)問題
PostCSS有一個(gè)問題,那就是它是零散的,所以我無法找到一個(gè)編輯器能正確地解析并高亮準(zhǔn)備使用PostCSS的css代碼。例如在WebStorm中我把它當(dāng)做普通的css文件,結(jié)果就會(huì)收到很多紅色的錯(cuò)誤提示。
所以,css預(yù)編譯器過時(shí)了嗎?
當(dāng)然不會(huì)。就像其他流行的框架和工具那樣,css預(yù)編譯器是已經(jīng)驗(yàn)證過的可用工具,我們完全可以根據(jù)需要選用。
Sass等css預(yù)編譯器的特點(diǎn)是成熟可靠。一方面,它們已經(jīng)是流行的模板語言,有完善的文檔和周邊支持,相對(duì)穩(wěn)定,新加入團(tuán)隊(duì)的人也能比較容易地理解。另一方面,集成的風(fēng)格有它的方便之處,就像你可能會(huì)懶得去組裝一個(gè)模型,但能找到專業(yè)的人替你完成。
PostCSS的特點(diǎn)則是模塊化。從長(zhǎng)遠(yuǎn)來看,PostCSS可以做到更多類型的css轉(zhuǎn)換。而可定制的風(fēng)格非常適合追求個(gè)性的人(更快捷,而且可以自己做出很有趣的插件)。
此外,css預(yù)編譯器和PostCSS可以協(xié)同使用。有一個(gè)流行的用法就是Sass編譯后再接PostCSS的Autoprefixer(畢竟這是PostCSS的招牌插件)。
結(jié)語
PostCSS的風(fēng)格可以說是在打造一個(gè)改變css開發(fā)方式的生態(tài)系統(tǒng)。所以如果說到未來,還是挺期待的。
相關(guān)文章
- CSS Grid 是一種二維布局系統(tǒng),可以同時(shí)控制行和列,相比 Flex(一維布局),更適合用在整體頁面布局或復(fù)雜模塊結(jié)構(gòu)中,這篇文章主要介紹了前端CSS Grid 布局詳解,需要的朋2025-04-16
CSS Padding 和 Margin 區(qū)別全解析
CSS 中的 padding 和 margin 是兩個(gè)非?;A(chǔ)且重要的屬性,它們用于控制元素周圍的空白區(qū)域,本文將詳細(xì)介紹 padding 和 margin 的概念、區(qū)別以及如何在實(shí)際項(xiàng)目中使用它們2025-04-07- will-change 是一個(gè) CSS 屬性,用于告訴瀏覽器某個(gè)元素在未來可能會(huì)發(fā)生哪些變化,本文給大家介紹CSS will-change 屬性詳解,感興趣的朋友一起看看吧2025-04-07
- 本文給大家分享在 CSS 中,去除a標(biāo)簽(超鏈接)的下劃線的幾種方法,本文給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2025-04-07
- 在前端開發(fā)中,CSS(層疊樣式表)不僅是用來控制網(wǎng)頁的外觀和布局,更是實(shí)現(xiàn)復(fù)雜交互和動(dòng)態(tài)效果的關(guān)鍵技術(shù)之一,隨著前端技術(shù)的不斷發(fā)展,CSS的用法也日益豐富和高級(jí),本文將2025-04-07
css中的 vertical-align與line-height作用詳解
文章詳細(xì)介紹了CSS中的`vertical-align`和`line-height`屬性,包括它們的作用、適用元素、屬性值、常見使用場(chǎng)景、常見問題及解決方案,感興趣的朋友跟隨小編一起看看吧2025-03-26淺析CSS 中z - index屬性的作用及在什么情況下會(huì)失效
z-index屬性用于控制元素的堆疊順序,值越大,元素越顯示在上層,它需要元素具有定位屬性(如relative、absolute、fixed或sticky),本文給大家介紹CSS 中z - index屬性的作用2025-03-21- 文章詳細(xì)介紹了CSS中的打印媒體查詢@mediaprint包括基本語法、常見使用場(chǎng)景和代碼示例,如隱藏非必要元素、調(diào)整字體和顏色、處理鏈接的URL顯示、分頁控制、調(diào)整邊距和背景等2025-03-18
CSS模擬 html 的 title 屬性(鼠標(biāo)懸浮顯示提示文字效果)
本文介紹了如何使用CSS模擬HTML的title屬性,通過鼠標(biāo)懸浮顯示提示文字效果,通過設(shè)置`.tipBox`和`.tipBox.tipContent`的樣式,實(shí)現(xiàn)了提示內(nèi)容的隱藏和顯示,感興趣的朋友一起2025-03-10前端 CSS 動(dòng)態(tài)設(shè)置樣式::class、:style 等技巧(推薦)
本文介紹了Vue.js中動(dòng)態(tài)綁定類名和內(nèi)聯(lián)樣式的兩種方法:對(duì)象語法和數(shù)組語法,通過對(duì)象語法,可以根據(jù)條件動(dòng)態(tài)切換類名或樣式;通過數(shù)組語法,可以同時(shí)綁定多個(gè)類名或樣式,此外2025-02-26