首頁  >  文章  >  web前端  >  從sass到PostCSS

從sass到PostCSS

高洛峰
高洛峰原創
2017-02-13 14:38:001389瀏覽

從sass到PostCSS 

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

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

  • 部分引用(partial import)

  • 變量(variables)

  • 嵌套(nesting)

  • 混合巨集(mixins)

  • 拓展(extend)

  • 佔位類(placeholder classes)

  • 準備工作
  • 在切換到新語法之後我需要做一些準備.現在項目的目錄結構是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樣式.

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

在Chrome的控制台裡我看到了很多404信息.這表示我們第一個丟失的特性就是內聯@import .tylergaw.css透過@import來引入CSS模組.瀏覽器看到這些,知道它要做什麼.瀏覽器會透過HTTP請求來載入每個模組.我的建置過程只複製了一個獨立的CSS檔案,而不是每個模組.正因如此,瀏覽器找不到它們.

我可以改變構建過程來讓默認的@import工作,但那樣效率很低.我需要一個Sass樣式內聯@import的替代品. 从sass到PostCSS

第一個插件

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

"scripts": {
  "postcss": "postcss -u postcss-import -o public/css/tylergaw.css src/css/tylergaw.css"
}
再次運行npm run postcss,單個的CSS文件就包含了所有模組.現在的頁面就展示出了部分樣式.

這會是CSS的未來嗎?

在Sass中展現出內聯方式的@import功能是非常強大的.它讓我們能更好的組織樣式.我不確定將來這個功能會不會原生支持.我們使用這種功能時總是需要一步編譯,看起來也不壞.


我想postcss-import插件會成為我PostCSS的一個主要配置,對其他人來說應該也一樣.下面引用了插件作者的看法:从sass到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 proSSdsext you can expect.

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

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

瀏覽器私有前綴

在構建這個網站之前我了解Autoprefixer.我用自定義Sass混合宏來解決添加所需要的前綴的問題.cssnext包含了Autoprefixer,所以我可以將這整個混合宏模組移除.

變量

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

[postcss-import]
這不是所有我使用的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 {
    & > p {...}
  }

  a {
    ...

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

    &::after {...}
  }

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

对于CSS嵌套,我将它修改为以下形式:

.projects-list {
  ...

  & li {
    & > p {...}
  }

  & 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的情况下正确且高效的编写样式.

从sass到PostCSS

带参数的混合宏

我用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.它们都允许你去使用未来的特性来编写代码.


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

第一步是列出我Sass用法的清單.我需要知道我使用了哪些特性,並且確信新特性在postCSS中有替代品.以下是我正在這個專案中使用的特性:

  • 部分引用(partial import)

  • 變數(variables)

  • 拓展(extend)

  • 佔位類(placeholder classes)

  • 顏色函數(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樣式.

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

从sass到PostCSS 在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文件就包含了所有模組.現在的頁面就展示出部分樣式.

這會是CSS的未來了嗎?
从sass到PostCSS 在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 proSSdsext you can expect.

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

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

瀏覽器私有前綴

在構建這個網站之前我了解Autoprefixer.我用自定義Sass混合宏來解決添加所需要的前綴的問題.cssnext包含了Autoprefixer,所以我可以將這整個混合宏模組移除.

變量

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

[postcss-import]

這不是所有我使用的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 {
    & > p {...}
  }

  a {
    ...

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

    &::after {...}
  }

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

对于CSS嵌套,我将它修改为以下形式:

.projects-list {
  ...

  & li {
    & > p {...}
  }

  & 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的情况下正确且高效的编写样式.

从sass到PostCSS

带参数的混合宏

我用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.它们都允许你去使用未来的特性来编写代码.


更多从sass到PostCSS 相关文章请关注PHP中文网!


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn