从sass到PostCSS

原文连接:tylergaw.com/articles/sa…
译者:Icarus
邮箱:xdlrt0111@163.comjavascript

多年来我一直使用Sass.可是最近我想要使用PostCSS和它的cssnext插件来尝试处理样式.我爱死了如今就可使用未来的CSS特性,相对于以前我用的工具,它们更顺手一些.个人我的站点就是尝试新特性的最好的测试地.css

第一步是列出我Sass用法的清单.我须要知道我使用了哪些特性,而且确信新特性在postCSS中有替代品.如下是我正在这个项目中使用的特性:java

  • 部分引用(partial import)node

  • 变量(variables)git

  • 嵌套(nesting)github

  • 混合宏(mixins)npm

  • 拓展(extend)json

  • 占位类(placeholder classes)浏览器

  • 颜色函数(darken and rgba color functions)sass

  • 压缩(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.它们都容许你去使用将来的特性来编写代码.

相关文章
相关标签/搜索