從sass到PostCSS

原文連接:https://tylergaw.com/articles...
譯者:Icarus
郵箱:xdlrt0111@163.comcss

多年來我一直使用Sass.可是最近我想要使用PostCSS和它的cssnext插件來嘗試處理樣式.我愛死了如今就可使用未來的CSS特性,相對於以前我用的工具,它們更順手一些.個人我的站點就是嘗試新特性的最好的測試地.node

第一步是列出我Sass用法的清單.我須要知道我使用了哪些特性,而且確信新特性在postCSS中有替代品.如下是我正在這個項目中使用的特性:git

  • 部分引用(partial import)github

  • 變量(variables)npm

  • 嵌套(nesting)json

  • 混合宏(mixins)瀏覽器

  • 拓展(extend)sass

  • 佔位類(placeholder classes)app

  • 顏色函數(darken and rgba color functions)函數

  • 壓縮(compression)

準備工做

在切換到新語法以後我須要作一些準備.如今項目的目錄結構是Sass的典型用法.我用下劃線(_)來命名文件,文件的拓展名爲scss.我使用兩個文件夾來組織Sass文件.moudules文件夾保存不直接產生CSS的Sass文件,像是變量、佔位類和混合宏.partials保存編譯出CSS的Sass文件.

這是最初的文件結構:

css/
  scss/
    modules/
      _module.scss
      ...
    partials/
      _partial.scss
      ...
    tylergaw.scss

每一個Sass組件會在tylergaw.scss中引入.

@import "modules/setup";
@import "modules/reset";
@import "modules/fonts";

我從新組織而且重命名了文件.我先把全部文件的後綴名從scss改成css.我使用了一個Bash腳原本完成這項工做,而不是一個一個修改.

`for f in *.scss; do git mv -- "$f" "${f%.scss}.css"; done;`

前面的下劃線是編寫Sass的習慣因此我也去掉了它.我沒辦法使用Bash命令一次性完成,因此只能手動每一個去修改.

最後一步就是將全部的CSS文件都移動至modules文件夾而且刪除partials文件夾.我認爲將全部CSS都當成modules來管理要比將他們按照moudules/partials拆分更容易理解.

環境搭建

我以PostCSS CLI爲起始,在package.json裏添加了一個臨時的構建腳本命令:

"scripts": {
  "postcss": "postcss -o public/css/tylergaw.css src/css/tylergaw.css"
}

在沒有更改任何樣式的狀況下我編譯了CSS:

`npm run postcss`

正常工做.控制檯沒有報錯,可是頁面上沒有任何CSS樣式.

A screenshot of tylergaw.com missing all styles

構建過程是可用的,如今的任務是把樣式找回來.

在Chrome的控制檯裏我看到了不少404信息.這表示咱們第一個丟失的特性就是內聯@import.tylergaw.css經過@import來引入CSS模塊.瀏覽器看到這些,知道它要作什麼.瀏覽器會經過HTTP請求來加載每一個模塊.個人構建過程只複製了一個獨立的CSS文件,而不是每一個模塊.正因如此,瀏覽器找不到它們.

我能夠改變構建過程來讓默認的@import工做,但那樣效率很低.我須要一個Sass樣式內聯@import的替代品.

第一個插件

postcss-import插件能夠代替Sass中的@import,在經過npm安裝以後,我更新了構建腳本代碼:

"scripts": {
  "postcss": "postcss -u postcss-import -o public/css/tylergaw.css src/css/tylergaw.css"
}

再次運行npm run postcss,單個的CSS文件就包含了全部模塊.如今的頁面就展現出了部分樣式.
A screenshot of tylergaw.com with partial styles

這會是CSS的將來嗎?

在Sass中展示出內聯方式的@import功能是很是強大的.它讓咱們能更好的組織樣式.我不肯定未來這個功能會不會原生支持.咱們使用這種功能時老是須要一步編譯,看起來也不壞.

我想postcss-import插件會成爲我PostCSS的一個主要配置,對其餘人來講應該也同樣.下面引用了插件做者的見解:

This plugin should probably be used as the first plugin of your list. This way, other plugins will work on the AST as if there were only a single file to process, and will probably work as you can expect.

[postcss-import](https://github.com/postcss/postcss-import#postcss-import)

cssnext

cssnext是PostCSS中一個插件,用於將將來CSS特性編譯爲現今支持的特性.特別須要指出,它和Sass或Less並不是不一樣的語言.它提供正在進行中的CSS規範的特性.一些特性已經獲得瀏覽器支持.另一些還處於規範的初始階段.

我使用cssnext來填補失去的Sass特性留下的鴻溝.

瀏覽器私有前綴

在構建這個網站以前我瞭解過Autoprefixer.我用自定義Sass混合宏來解決添加所須要的前綴的問題.cssnext包含了Autoprefixer,因此我能夠將這整個混合宏模塊移除.

變量

下一步我將Sass變量改成CSS自定義屬性.好比在_setup.scss中,我這樣寫:

$grey: #1e1e1d;
$yellow: #ffad15;
$offwhite: #f8f8f8;
$darkerwhite: darken($offwhite, 15);

這不是全部我使用的Sass變量,可是主要就這些.剩下都在獨立的模塊中.

注意: 自定義屬性和變量的區別.CSS自定義屬性只在屬性值有效,不能用於選擇器,屬性名或媒體查詢.

新的setup.css:

:root {
  --white: #fff;
  --grey: #1e1e1d;
  --yellow: #ffad15;
  --offwhite: #f8f8f8;
  ...
}

如下爲使用示例:

a {
  color: var(--yellow);
}

除了語法,CSS自定義屬性和Sass變量工做方式是相同的.因爲瀏覽器支持的限制,自定義屬性值仍然須要編譯.在上面的示例中,編譯後的值爲color: #ffad15.

顏色函數

在以前的例子中,我遺漏了一個變量:$darkerwhite: darken($offwhite, 15);.這是另外一個我須要尋找替代的Sass特性.這裏有一個規範草案提供CSS顏色函數.cssnex如今包含這些函數,這很是酷.下面是setup.css,其中darkerwhite自定義屬性是經過顏色函數和陰影調節器來實現的.

:root {
  ...
  --offwhite: #f8f8f8;
  --darkerwhite: color(var(--offwhite) shade(20%));
  ...
}

顏色函數提供了許多調節器.你能夠在一個函數中使用多個調節器:

`background-color: color(#d32c3f shade(40%) alpha(40%));`

編譯結果爲:

`background-color: rgba(127, 26, 38, 0.4);`

再次重申,如今cssnext會將color()編譯爲16進制或rgba的色值.當顏色函數獲得瀏覽器支持後,編譯過程就沒有必要了.顏色操做在運行時就能夠發生.

嵌套

嵌套是CSS預處理器不可或缺的特性.任何讓人舒服的樣式工具的必需品.Tab Atkins對CSS嵌套有一個正在進行中的規範,而且cssnext讓它成爲現實.

CSS的嵌套語法包含一個前置於內層的&,如下爲sass片斷:

.projects-list {
  ...

  li {
    & > div {...}
  }

  a {
    ...

    &:hover,
    &:focus {...}

    &::after {...}
  }

  @media (min-width: 640px) {...}
}

對於CSS嵌套,我將它修改成如下形式:

.projects-list {
  ...

  & li {
    & > div {...}
  }

  & a {
    ...

    &:hover,
    &:focus {...}

    &::after {...}
  }

  @media (min-width: 640px) {...}
}

基本的嵌套須要前置的&.僞類和選擇器在Sass和CSS中是相同的.媒體查詢不須要前置&.

另外值得注意的是@nest.正如文檔中提到的,複雜的嵌套可能須要引入@nest來代替&.這個項目我尚未用到,或許未來用獲得.

拓展和佔位類

Sass中的@extend和佔位類是我常用的兩個特性。下面是Futura頭部的樣式示例:

%futura {
  font-family: 'futura-pt', helvetica, sans-serif;
}

%futura-heading {
  @extend %futura;
  font-weight: 700;
  line-height: 1.1;
  text-transform: uppercase;
}

這是一個用例:

.my-heading {
  @extend %futura-heading;
}

我在以前瞭解過CSS自定義屬性的用法。這裏有一個正在進行中的@apply規則的規範與之相關。@apply容許儲存一系列的屬性而且在選擇器引用。我用@apply來代替Sass的extend.

回到setup.css來,我更新了Futura頭部的屬性:

:root {
  ...

  --franklin: {
    font-family: 'futura-pt', helvetica, sans-serif;
  };

  --franklin-heading: {
    @apply --franklin;
    font-weight: 700;
    line-height: 1.1;
    text-transform: uppercase;
  };
}

這裏是一個示例:

.my-heading {
  @apply --franklin-heading;
}

@apply不是繼承.在目前的cssnext中,@apply將屬性和值直接複製到每條規則中.這是個小項目因此沒問題.可是在大型的項目中,可能會致使樣式冗餘,項目很是臃腫.這種狀況下最好仍是使用通用類名來適用類似狀況.

如今個人網站看起來和以前同樣了.項目頁是個例外.它的每一個磁貼區域都有不一樣顏色.接下來我會解釋怎麼在沒有Sass的狀況下正確且高效的編寫樣式.

A screenshot of tylergaw.com/projects

帶參數的混合宏

我用Sass的混合宏來讓項目編寫樣式更簡便.這個混合宏有一個磁貼顏色的參數.如下是這個project-block的混合宏.

@mixin project-block ($c) {
  background-color: $c;

  a {
    color: $c;

    &:hover {
      background-color: $c;
      color: $offwhite);
    }
  }
}

下面是一個示例:

.p-jribbble {
  @include project-block(#ff0066);
}

在寫這篇文章的時候,我尚未在CSS找到能模擬這個功能的特性.自定義屬性配合@apply不是函數,因此咱們不能爲它傳遞參數.在未來,自定義選擇器可能會容許使用參數.在草案規範中有一個看起來頗有前途的複雜示例.但我認可如今我還沒徹底明白它是怎麼工做的.

這不意味着我運氣很差.我寫CSS的時間要長於Sass,但也沒多久.我還用了另外一個正進行中的規範特性,matches選擇器.

下面是一個代替project-block混合宏的CSS示例:

.p-jribbble,
.p-jribbble a:matches(:hover, :focus) {
  background-color: var(--color-jrb);

  & a {
    color: var(--color-jrb);
  }
}

顏色變量是早些在文件中:root做用域定義的.cssnext將以上CSS編譯爲:

.p-jribbble,
.p-jribbble a:hover,
.p-jribbble a:focus {
  background-color: #ff0066
}

.p-jribbble a,
.p-jribbble a:hover a,
.p-jribbble a:focus a {
  color: #ff0066;
}

最後兩個選擇器...a a:hover...a a:focus匹配不到任何元素.他們是沒必要要的.可是除了佔用幾比特的空間他們也沒有任何影響.爲了代碼的可讀性,我更傾向於a選擇器的嵌套.

更多PostCSS特性

爲了樣式按順序迴歸,我決定利用更多的PostCSS插件.我用css mqpacker來合併使用相同查詢條件的媒體查詢.我也用cssnano來優化代碼.

這也是爲何我期待去使用PostCSS.使用Sass的時候我感受困在當前的特性中.但由於PostCSS本質是一個插件集合在工做,更具拓展性.若是我有特殊須要,我能夠本身來寫一個插件.它的潛力使人興奮.

我妥協了

在使用這個新工具工做了幾天後,我徹底投入進去了.從Sass轉向新的CSS語法很是簡單,而且是在五六年間我每一個項目都用Sass編寫的狀況下.

我喜歡這個思想轉變.cssnext對CSS的處理很像Babel對Javascript.它們都容許你去使用將來的特性來編寫代碼.

相關文章
相關標籤/搜索