CSS預編譯與PostCSS以及Webpack構建CSS綜合方案

原文連接javascript

CSS全稱Cascading Style Sheets(層疊樣式表),用來爲HTML添加樣式,本質上是一種標記類語言。CSS前期發展很是迅速,1994年哈肯·維姆·萊首次提出CSS,1996年12月W3C推出了第一個正式版本。隨後不到兩年的時間,1998年5月便推出了第二個版本,一直沿用至今。可是CSS3的制訂工做卻遲遲沒有完成。CSS3最初的草案在1999年便被提出,可是直到今日CSS3規範仍然有部分特性沒有完成。若是說ES6與ES5相隔的6年時間讓開發者們熬盡了心肝,那麼從提案到發佈相隔近20年光陰的CSS3能夠說是千呼萬喚始出來,並且猶抱琵琶半遮面。css

CSS的缺陷

CSS的初衷是爲了彌補HTML原生樣式的不足,早期對樣式要求並不複雜的web網站僅僅須要少許的CSS代碼便可。在現在web應用程序追求極致用戶體驗的潮流下,對CSS的要求也不斷加強。複雜CSS開發是一件很是痛苦的事情,最主要的緣由是受限於瀏覽器的實現以及CSS自身的弱編程能力:html

  1. 瀏覽器實現不理想甚至實現方案各一。對CSS的兼容處理幾乎是每一個前端工程師必備的技能,究其根本是瀏覽器對CSS規範的實現程度和方案不一。其中尤以IE瀏覽器最甚,包括以IE內核的衆多國產瀏覽器。雖然目前絕大多數web應用已經不在兼容IE8如下瀏覽器,但IE8和IE9仍然讓前端工程師們頭疼不已;
  2. CSS的弱編程能力。CSS經過「selector-properties」的模式爲HTML文檔增長樣式,簡單的語法可讓沒有任何編程基礎的初學者或者設計人員很快上手。但CSS不支持嵌套,甚至運算、變量、複用等這些幾乎是編寫複雜代碼的必備特性。從CSS3引入了cal()以及處於草案階段的var()能夠隱約看出W3C有意增強CSS的編程能力;

開發者們不斷探索着可以彌補這些缺陷的解決方案,CSS預編譯器是第一種順勢而生的革命性方案。前端

CSS預編譯

CSS預編譯的工做原理是提供便捷的語法和特性供開發者編寫源代碼,隨後通過專門的編譯工具將源碼轉化爲CSS語法。最先的CSS預編譯器是2007年起源於Ruby on Rails社區的SASS,目前比較流行的其餘CSS預編譯器如Less、Stylus的誕生都必定程度上受到了SASS的影響和啓發。java

CSS預編譯器幾乎成爲現現在開發CSS的標配,它從如下幾個方面提高了CSS開發的效率:webpack

  1. 加強編程能力;
  2. 加強可複用性;
  3. 加強可維護性;
  4. 更便於解決瀏覽器兼容性。

不一樣的預編譯器特性雖然有所差別,但核心功能均圍繞這些目標打造,好比:web

  • 嵌套;
  • 變量;
  • mixin/繼承;
  • 運算;
  • 模塊化;

嵌套是全部預編譯器都支持的語法特性,也是原生CSS最讓開發者頭疼的問題之一;mixin/繼承是爲了解決hack和代碼複用;變量和運算加強了源碼的可編程能力;模塊化的支持不只更利於代碼複用,同時也提升了源碼的可維護性。編程

PostCSS

CSS預編譯的理念與Babel有必定相通之處,最重要的區別是:預編譯語法並不是規範的CSS,而是各成一派。由預編譯語法編寫的源代碼不能在任何宿主瀏覽器中運行。從這個角度考慮,CSS預編譯更像CoffeeScript、TypeScript等JavaScript子集。能夠預見的是,若是將來CSS規範推出了預編譯相似的特性和語法,這些預編譯器都將成爲歷史的塵埃。PostCSS則反其道而行之,從理念上更加接近Babel,業內也有人將其稱爲「CSS的Babel」。瀏覽器

PostCSS鼓勵開發者使用規範的CSS原生語法編寫源代碼,而後配置編譯器須要兼容的瀏覽器版本,最後通過編譯將源碼轉化爲目標瀏覽器可用的CSS代碼。PostCSS提供了豐富的插件用於實現不一樣場景的編譯需求,最經常使用的好比autoprefixer、sprites等,編譯流程以下圖所示:
前端工程師

PostCSS並非另外一種CSS預編譯器,與SASS、Less等預編譯器也並不衝突。PostCSS與Babel的不一樣之處在於,它所支持的所謂「將來CSS語法」並非嚴格的CSS規範,其中大部分語法和特性目前只是CSS4的草案而已。不少人將PostCSS稱爲「CSS後編譯器」,這個稱謂能夠必定程度上說明目前業界對PostCSS的廣泛使用方案,請看下圖:

即便是PostCSS支持的「將來CSS語法」也並不能徹底彌補CSS的缺陷,因此目前廣泛的方案是將CSS預編譯與PostCSS綜合在一塊兒:

  • 使用CSS預編譯彌補CSS源碼的弱編程能力,好比變量、運算、繼承、模塊化等;
  • 使用PostCSS處理針對瀏覽器的需求,好比autoprefix、自動css sprites等。

Webpack結合預編譯與PostCSS實現CSS構建

經過Webpack配置項中的use指定的loader是按照索引反向執行,好比存在下述配置方案:

{
  test: /\.less$/,
  use: [
    'style-loader',
    'css-loader',
    'less-loader'
  ]
}

.less後綴類型的文件依次通過less-loadercss-loaderstyle-loader編譯。在這種工做模式的基礎上,結合圖3-4所示的編譯流程,使用Webpack結合CSS預編譯與PostCSS的編譯方案便一目瞭然了:

{
  test: /\.less$/,
  use: [{
    loader: 'style-loader',
    options: {} // style-loader options
  },{
    loader: 'css-loader',
    options: {
      importLoaders: 2 // css-loader options
    } 
  },{
    loader: 'postcss-loader',
    options: {} // postcss-loader options
  },{
    loader: 'less-loader',
    options: {} // less-loader options
  }]
}

上述配置中有如下須要注意的細節:

  1. css-loader中importLoaders選項的做用是用於配置css-loader做用於 @import 的資源以前須要通過其餘loader的個數。@import 用於css源碼中引用其餘模塊的關鍵字,若是你的項目中肯定不會涉及模塊化能夠忽略此配置項;
  2. 若是須要將編譯後的css文件獨立導出,則需將style-loader[注]替換爲extract-text-webpack-plugin,以下:
{
  test: /\.less$/,
  use: ExtractTextPlugin.extract({
    filename: './dest/[name].[contenthash].css'
    use: [{
      loader: 'css-loader',
      options: {
        importLoaders: 2 // css-loader options
      } 
    },{
      loader: 'postcss-loader',
      options: {} // postcss-loader options
    },{
      loader: 'less-loader',
      options: {} // less-loader options
    }],
    publicPath: '/'
  })
}

注:不少開發者容易混淆css-loader和style-loader的做用。css-loader的做用是解析css源文件並獲取其引用的資源,好比@import引用的模塊、url()引用的圖片等,而後根據Webpack配置編譯這些資源。style-loader負責將css代碼經過<style>標籤插入html文檔中,因此若是獨立導出css文件就再也不須要style-loader。css-loader必須在style-loader以前執行。

相關文章
相關標籤/搜索