繼上一次PostCSS學習指南(一)後,漸漸開始在項目中應用。javascript
此次決定主要講解一些我的認爲很是有幫助的PostCSS插件。css
本期主要介紹如下幾個插件和幾個坑java
這個就不用多說了,必裝插件之一。方便的寫規範的css,它會爲你提供很是完整的hack兼容方案的。固然這裏須要瞭解一下的是,它的大部分兼容數據來源Can I Use,另一個稍微須要瞭解的插件配置參數就是browsers,好比這樣寫:node
module.exports = { plugins: [ require('autoprefixer')({ browsers: 'last 2 versions' }) ] }
關於這個參數的詳細介紹能夠看看Browserslist Queries,文中說了,強烈建議將查詢寫入package.json(後面會告訴你爲什麼要寫在這裏),而非配置postcss.config.js中autoprefixer的browsers參數。因此此處建議寫法以下:webpack
postcss.config.jsgit
module.exports = { plugins: [ require('autoprefixer'); ] }
package.json內增長以下示例github
"browserslist": [ "> 1%", "last 2 versions" ]
這裏我對着官方文檔簡單說一下數組內的值對應的含義:web
last 2 versions
: 每一個瀏覽器中最新的兩個版本。> 5%
or >= 5%
: 全球瀏覽器使用率大於5%或大於等於5%(上例中則是1%)。其餘的一些參數簡單介紹:json
ie 6-8
: 選擇包含ie6-8的版本。Firefox > 20
: 火狐版本號大於20。還有不少不一一列舉,這裏的配置仍是很詳細的,通常來講最省事的就是不加參數,按照默認便可。segmentfault
須要配置的話,就在package.json裏面添加browserslist
參數,這樣其餘插件也可以從中獲取到項目將要兼容的版本,目前包含如下幾個插件會讀取改配置:
關於autoprefixer的介紹差很少就這些了~
這個沒啥好說的,也是很容易理解的插件,就是讓你的css文件支持@import
,支持W3C的寫法也支持SASS那種寫法,這裏就很少說啦。
一樣的,像SASS那樣能夠自定義變量並進行引用,用法也十分簡單,相信你們必定不用點開官方文檔也會用的~(你確定仍是點開了哈哈哈~你這叫胡開連接綜合症,生怕錯過了啥內容。)
很顯然這個插件做者比較高調,github的cssnano上面是沒有什麼說明和介紹的,固然官方也寫得很詳細了。這個插件給個人感受就是css代碼壓縮工具(實際上它集成了不少強化的功能,表面上看起來是壓縮實際上進行了至關多處理,能夠看看這個表格Optimisations),他的配置建議採用默認配置,除非你知道你在作什麼。
固然我在測試使用中遇到了一點點問題,關於cssnano和autoprefixer結合使用,或者說是postcss.config.js插件引入順序有關的形成輸出不一樣的問題?我暫時還在研究,先看代碼:
testcssnano.css
.test { -moz-border-radius: 10px; border-radius: 10px; display: flex; }
postcss.config.js(第一種)
module.exports = { plugins: [ require('cssnano')({ preset: 'default', }), require('autoprefixer') ] }
輸出結果:
.test{border-radius:10px;display:flex}
postcss.config.js(第二種)
module.exports = { plugins: [ require('autoprefixer'), require('cssnano')({ preset: 'default', }) ] }
輸出結果:
.test{border-radius:10px;display:-webkit-box;display:-ms-flexbox;display:flex}
問題一,若是手寫-moz-
,cssnano會清除,可見示例,固然或許這個屬性在火狐已經支持不需前綴因此,就被去掉了。
問題二,若是在配置文件中,cssnano在autoprefixer以前引用,假設根據webpack的loader執行順序規則相同的話,大概postcss.config.js中的插件也是這樣由下而上依次執行,所以,在第一種例子中,css代碼先被autoprefixer處理,而後再執行cssnano清除了那些多餘的前綴代碼?大體可分解爲:
第一步autoprefixer處理結果:
.test { -moz-border-radius: 10px; border-radius: 10px; display: flex; display: -webkit-box; display: -ms-flexbox; }
第二步cssnano處理結果:
.test{border-radius:10px;display:flex}
但是我要遺憾的告訴你們。。。這個多是錯誤的結論!!!
由於我將第一步的結果做爲初始css,將postcss.config.js中僅引用一個cssnano插件來執行的結果以下:
.test{border-radius:10px;display:flex;display:-webkit-box;display:-ms-flexbox}
所以,這個問題就來了。。。cssnano確實將-moz-
去掉,可是他並無處理其餘的關於display的兼容代碼。
因而我再作了一個測試:
我將css代碼改成:
.test { -webkit-transform: scale(.5) translate(10, 20); -moz-transform: scale(.5) translate(10, 20); -ms-transform: scale(.5) translate(10, 20); -o-transform: scale(.5) translate(10, 20); transform: scale(.5) translate(10, 20); }
而postcss.config.js仍是同時引入cssnano和autoprefixer,通過測試,不管誰先誰後輸出結果均爲:
.test{-webkit-transform:scale(.5) translate(10,20);transform:scale(.5) translate(10,20)}
若是css代碼改成:
.test { transform: scale(.5) translate(10, 20); }
postcss.config.js同時引入cssnano和autoprefixer,
第一種cssnano在前結果:
.test{transform:scale(.5) translate(10,20)}
第二種autoprefixer在前結果:
.test{-webkit-transform:scale(.5) translate(10,20);transform:scale(.5) translate(10,20)}
結果又不同,不知道看到這裏你們暈了沒有。
根據觀察,postcss.config.js的插件執行順序是有要求的,至少在同時使用cssnano和autoprefixer的時候,cssnano必定要在autoprefixer以後,不然autoprefixer可能會失效!
另外cssnano和autoprefixer都會對很舊的兼容寫法進行精簡,例如上文有一段有不少個transform屬性的css代碼,autoprefixer會(根據browserslist)剔除其餘的。
至於順序問題,我後面繼續進行研究!
作移動端,適配是個頭疼的問題,不過我目前仍是使用想對穩定的方案flexible,那麼就須要用rem來作主要的單位,這裏不說適配問題只說這個插件,通常移動端,設計師給的設計稿都是750px寬,你只須要下面這樣設置,就能夠直接在代碼裏面寫你在PSD量的像素值了,這真是太使人激動了!
require('postcss-px2rem')({ remUnit: 75, threeVersion: true })
由於這個postcss-px2rem又是來源於px2rem的,因此詳細的說明見px2rem,我這裏寫了兩個參數,一個remUnit,這個對應的是每rem對應的px值,既然750px,就寫75啦,不知道這樣理解對不對。另外一個threeVersion則對應三個不一樣dpr下的大小,這個比較少用,須要注意的是處理這些參數,是否轉換rem都和註釋有關,這裏就不細說了,看看文檔就好~固然這裏也埋下一個坑,等下會提到。
這就是個大雜燴,主要是爲了知足SASS開發者的習慣,繼承了不少插件,本篇先後文都有說起precss內的部分插件,若是並非所有用到,我建議仍是一個個手動安裝所需插件來進行配置,這東西,配好了之後也就不會常常改動了,並且我的認爲用大雜燴很容易出現一些坑,又很難排查,例以下面兩個插件,你們仔細看看。
另外還有幾個插件,建議安裝(固然若是你徹底不知道幹啥的能夠忽略):
其餘的一些我我的以爲不經常使用或者說實用意義不大因此就沒有寫出來了。
這兩個也是從precss裏面拿出來的,就是仿SASS的嵌套css寫法用。爲啥把這兩個放一塊兒寫,由於他們長的太像了。只看名字鬼知道他們的區別,然而他們都被加入到precss裏面去了。據precss介紹,他們兩個的區別是:
光看這兩行我是看不懂究竟是個啥玩意,難道第一個是符合W3C規範的嵌套選擇?粗略看了下兩個插件的說明文檔,沒看出沒啥區別。行,那手動寫代碼來一個個試試。先安裝postcss-nesting,編譯試試,譁嚓一片紅。。。咋回事,咱們先看看代碼片斷。
.catis-list { padding: 0 50px; overflow: hidden; li { list-style: none; float: left; margin-top: 38px; width: 113px; &:not(:nth-child(4n)) { margin-right: 66px; } .iconfont { font-size: 100px; line-height: 100px; color: #506071; display: block; text-align: center; } .cati-name { font-size: 28px; line-height: 40px; display: block; color: #999; text-align: center; } } }
看似SASS寫法沒有任何問題。但是它提示的報錯信息讓人看不大懂
ERROR in ./src/style/index.css Module build failed: ModuleBuildError: Module build failed: Error: undefined:783:6: property missing ':' at error (D:\webProjects\mobileweb\node_modules\css\lib\parse\index.js:62:15) at declaration (D:\webProjects\mobileweb\node_modules\css\lib\parse\index.js:223:33) at declarations (D:\webProjects\mobileweb\node_modules\css\lib\parse\index.js:252:19)
啥玩意missing了個冒號嘛。。。改來改去都不對。索性拿來官方的實例。纔看清楚。原來每一個嵌套的樣式前面都須要一個&
(注意符號後面有個空格),實際上應該以下才對:
.catis-list { padding: 0 50px; overflow: hidden; & li { list-style: none; float: left; margin-top: 38px; width: 113px; &:not(:nth-child(4n)) { margin-right: 66px; } & .iconfont { font-size: 100px; line-height: 100px; color: #506071; display: block; text-align: center; } & .cati-name { font-size: 28px; line-height: 40px; display: block; color: #999; text-align: center; } } }
這裏面有一段用到僞類其中&符號後面是沒有空格的,是正確的。編譯後的結果:
.catis-list { padding: 0 0.666667rem; overflow: hidden; } .catis-list li { list-style: none; float: left; margin-top: 0.506667rem; width: 1.506667rem; } .catis-list li:not(:nth-child(4n)) { margin-right: 0.88rem; } .catis-list li .iconfont { font-size: 1.333333rem; line-height: 1.333333rem; color: #506071; display: block; text-align: center; } .catis-list li .cati-name { font-size: 0.373333rem; line-height: 0.533333rem; display: block; color: #999; text-align: center; }
那麼這樣就沒有問題了。和官方的說明的是同樣的,可是另外一方面,若是每次都要寫&加空格,那豈不是很麻煩,習慣寫SASS的兄弟們確定不肯意這樣作啦。
那麼我要說的就是另外一個插件postcss-nested,如precss所述,這個的確是SASS-LIKE了。固然我暫時還不太明白爲什麼precss要收入兩個nest插件(爲了知足不一樣開發人員的習慣?)。咱們修改postcss.config.js使用postcss-nested,並從新修改樣式代碼以前第一段,再次編譯執行,一切OK,那麼結論就是,若是僅習慣於SASS的嵌套寫法,安裝postcss-nested插件便可~
postcss-partial-import
這個理應是第一個引入的,你如果把它放在最後面,而css代碼中第一行就用了@import
那確定會報錯!因此,建議根據css代碼的寫法來決定你的執行順序。postcss-nested插件是大部分SASS開發者所喜好的,可是你在css文件中用sass寫法會遇到如下幾個問題:
csslint,css文件不支持嵌套,變量等寫法,若是你將文件模式改成sass,註釋的方式會變成//
,而非/* comments */
,固然你能夠手寫/* ... */
這樣的註釋,可是用快捷鍵進行註釋會很痛苦。
這裏有個小技巧,讓項目全部css文件均爲sass模式下編輯,在項目settings.json添加:
"files.associations": { "*.css": "scss" }
固然你如果想要支持//
註釋也是能夠的,請再安裝postcss-scss插件,我這裏很少說這個了,由於我已經決定手寫註釋了?
你手寫註釋沒有問題,然而編譯出來的東西會出問題,你樣式中最後一行若是將註釋寫在花括號內部,它轉換出來的代碼,註釋會在外部,這是個大坑,由於在使用postcss-px2rem的時候,那註釋來控制是否轉換的功能就失效了。我文字描述可能讓人迷糊,因此看看代碼:
例如CSS部分代碼:
.test { color:#999; border:1px solid #ddd; /* no */ .inner { color:#333; } }
轉換後:
.test { color:#999; border:0.13333rem solid #ddd; } /* no */ .test .inner { color:#333; }
而不是我想要的:
.test { color:#999; border:1px solid #ddd; } .test .inner { color:#333; }
理論上是應該輸出我想要的結果,卻沒有輸出正確,錯誤的將1px的border轉成rem,緣由就是先執行的postcss-nested將註釋弄在外部後,postcss-px2rem沒法識別到它的規則了。
我一開始也是裝了precss後發現該問題,後來查了好久才發現是這個插件的問題。同時也發現了這我的其實已經提過issue了Wrong location of comment of the last declaration in a nested rule definition只是沒人解決。
而我臨時處理的方法就是隻好將要註釋的那段代碼不要寫在最後一行了。以下:
.test { border:1px solid #ddd; /* no */ color:#999; .inner { color:#333; } }
可能有時候並不會有兩個樣式給border墊底,若是隻有一行border的樣式,就只能這樣:
.test { .inner { color:#333; } border:1px solid #ddd; /* no */ }
這樣卻是能夠了,不過看起來很奇怪,因此若是你使用和我相同的處理方式時,務必注意此點(寫完本文時我彷佛發現了更好的解決方案,等確認了沒有問題後,放在下一期來寫~)。
(我記得好像還有坑的,硬是想了半天想不起來了。。。那就先這樣吧)
最後若是你還想探索更多好玩的好用的插件,你能夠看看這裏PostCSS Plugins List還有這個能夠搜索的分類插件列表,若是你發現了更棒的插件,也歡迎留言喔~
另外上面的例子若是我沒有寫的很明白,或者你只是想直接拿來快速測試使用的話,能夠看看這個mobileweb
(關於第三期PostCSS的內容還在考慮。。。多是對第二期的補充和填坑~敬請期待?)
關於我我的的PostCSS一系列學習, 介紹及總結, 有興趣能夠參閱: