PostCSS深入学习: 定制自己的预处理器

上一篇文章中,我们学习了如何使用PreCSS这款优秀的预处理器插件包。在这篇文章中我们将基于PostCSS的基础上以不同的方式构建一个预处理器。你可以精心挑选一些优秀的PostCSS插件,自定义构建一款属于自己的预处理器。

通过我个人一些发现,通过设置一些插件带你定制一个强大的预处理器。当然,你可以选择我下面提到的插件,你也可以选择你喜欢的插件来定制属于自己的预处理器。

无论你选择哪些来设置,而下面介绍的只是定制预处理器的一个过程。也就是说,这篇文章的目的是让你通过PostCSS一些插件,手动定制预处理器,这个过程让你掌握一些定制经验。这样你就可以自己决定使用哪一个插件,来填补你自己需要的功能。

让我们开始吧。

设置您的项目

你需要做的第一件事情是使用Gulp或Grunt设置你的项目。如果你没有一个较好的项目模板,你可以使用Gulp或者Grunt使用最少的代码来达到相同的目的。

你可以阅读前面有关于PostCSS的教程,了解有关于如何使用Gulp或Grunt设置您的项目:

如果你不想从头开始手动设置您的项目,你可以下载本教程中提供的源码附件,提取Gulp或Grunt项目到一个空的文件夹中。

然后在命令终端运行:npm install

插件的安装

如果你看过了前面的教程,你应该熟悉如何将PostCSS插件安装到你的项目中,并且知道怎样通过gulpfile.jsgruntfile.js加载需要的PostCSS插件。

重要的是:如果你看了《PostCSS深入学习: 管理插件》一文,一定要注意通过gulpfile.jsgruntfile.js加载插件时要注意插件加载的顺序,切保插件能正常运转。

使用@import

开始整理我们自定义的预处器时,我们第一个要说的就是@import。在前面的《PostCSS深入学习: 压缩和优化CSS》和《PostCSS深入学习: PreCSS的使用》教程中,你都看到了PostCSS通过@import将样式表合并到一起。那么@import用于自定义的预处器上也不例外。

上面我们只是感觉到PostCSS插件加载顺序非常重要,在这里,将@import做为第一个例子,就是想要确保所有内联样式能过@import来导入。将此做作为第一步。

例如,我们可以会将所有的变量放在一个文件中,然后通过@import将其导入到主样式表中。如果我们不先运行@import插件,我们的变量就不会被导入,从而其他的地方就没办法使用定义好的变量。

改变gulpfile.jsstyle.css的源文件

因为要开始介绍使用@import功能导入文件(partials),在添加@import功能之前,需要先对gulpfile.js文件做下调整。

注:如果你项目中使用的是Grunt,那么在这个阶段你不需要做任何的修改。

现在把很多.css文件放在src文件夹下,这样就有很多样式文件需要编译,但是又不想编译partial文件。我们可以将所有文件都导入到style.css中,这样就只需要编译一个文件就可以。

gulpfile.js文件中找到这行代码:

return gulp.src('./src/*.css')

然后修改成:

return gulp.src('./src/style.css')

Import插件的使用

在《PostCSS深入学习: 压缩和优化CSS》一文中介绍了相同的插件,这款插件也用在了PreCSS插件包中,所以对于你来说会比较熟悉(前提是你阅读了这个系列的前面几篇文章)。

将插件安装到你的项目中,然后在src文件夹中创建一个_vars.css的文件名,并且在这个文件中添加一些测试代码。注意,我们还没有添加变量功能,因此先在这里面写点CSS代码,如:

.test {    background: black;}

src/style.css文件中第一行添加下面的代码,就可以将新创建的变量文件导入到src/style.css文件:

@import "_vars";

编译之后,你去查看dest/style.css文件,你就可以看到文件中已经包含了_vars.css文件中的代码。

添加混合宏

混合宏插件的使用

注意,这个插件必须运行在postcss-nestedpostcss-simple-vars插件之后,这两个插件我们都将会用到。

postcss-mixins插件安装到你的项目中,并在src/style.css文件中添加下面的代码:

@define-mixin icon $network, $color {    .button.$(network) {        background-image: url('img/$(network).png');
        background-color: $color;
    }}@mixin icon twitter, blue;

编译之后,在dest/style.css文件中你可以看到编译后的代码:

.button.twitter {    background-image: url('img/twitter.png');
    background-color: blue;}

在PreCSS这个插件包中也包括了postcss-mixins插件。在《PostCSS深入学习: PreCSS的使用》中详细介绍了如何使用混合宏。

其他的混合宏插件

如果你喜欢Sass的语法,那么你使用了@Andy Jansson的postcss-sassy-mixins插件,他的工作方式和postcss-mixins类似,这样你就可以使用@mixin定义混合宏,然后通过@include调用定义好的混合宏。

添加for循环

for循环插件的使用

注意,postcss-for插件必须运行在postcss-nestedpostcss-simple-vars插件之前。

在项目中安装postcss-for插件,然后在src/style.css文件中加入下面的测试代码:

@for $i from 1 to 3 {    p:nth-of-type($i) {        margin-left: calc( 100% / $i );
    }}

编译出来的CSS:

p:nth-of-type(1) {    margin-left: calc( 100% / 1 );}p:nth-of-type(2) {    margin-left: calc( 100% / 2 );}p:nth-of-type(3) {    margin-left: calc( 100% / 3 );}

再说一次,在PreCSS插件包使用了相同的@for循环,所以在前面的《PostCSS深入学习: PreCSS的使用》教程中可以了解有关于@for循环更详细的信息。

其他for循环插件选项

前面提到过postcss-for插件必须运行在postcss-simple-vars插件之前。因为运行在其之后,就没有办法给@for循环设置变量。

如果你觉得这是一个问题,你可以在Github上面将postcss-for库fork一份出来,然后个修改一下相关参数,让其在postcss-simple-vars后加载。

这样你就可以在@for循环中使用变量:

@from: 1;@count: 3;@for $i from @from to @count {    p:nth-of-type($i) {        margin-left: calc( 100% / $i );
    }}

添加变量

给预处理器添加变量有两种方法,这两种方法都非常的方便。第一种是使用类似于Sass语法,而第二种是CSS的变量,也称为CSS自定义属性

变量插件使用

将这两个插件安装到你的项目中,然后我们将会每个测试。

首先,来测试类似Sass语法的postcss-simple-vars插件。打开你项目中的_vars.css文件,并添加下面的代码:

$default_padding: 1rem;

接着在src/style.css文件中添加下面的代码:

.post {    padding: $default_padding;}

编译出来,dest/style.css你看到的代码会像这样:

.post {    padding: 1rem;}

接下来测试类似于CSS自定义属性的postcss-css-variables插件,并且把下面的测试代码添加到src/style.css文件中:

:root {    --h1_font_size: 3rem;}

h1 {
    font-size: var(--h1_font_size);}

@media ( max-width: 75rem ){
    h1 {        --h1_font_size: 4vw;
    }
}

编译之后,dest/style.css里看到编译后的CSS代码如下:

h1 {    font-size: 3rem;}@media ( max-width: 75rem ) {    h1 {        font-size: 4vw;
    }}

注意,当使用CSS变量,在媒体查询中只需要修改--h1_font_size变量的值,就能自动输出相关的font-size大小。这功能对于媒体查询来说是特别有用的。

为什么使用用两种类型的变量?

再次说一下,本教程中所采用的方法不是你必须得采取的方法。如果你只想使用其中一个变量插件,而不想使用其他的,这完全是没有问题的。

从我自身的角度来看,我之所以喜欢使用这两种类型的变量,是我自己会在不同的地方使用它们。通常会在我的主样式文件表中使用CSS变量,而在我的局部样式表中,我会使用类似于Sass的变量。

另外,当CSS变量得到浏览器支持时,在我的项目中就可以开始使用CSS变量类型。另外从上面的示例中可以看到,CSS变量有些功能对于Sass这样的变量是无法提供的。

与此同时,使用类型于Sass这样的变量不属于生活(live)样式表的事情,尤其是寻些纯粹为了每个循环条件提供的变量。

其他的变量插件

如果你想替换postcss-simple-vars插件,你可以考虑使用postcss-advanced-variables插件,而且这个插件也是PreCSS插件包中的一部分。

这也是一个很好的选择,主要区别是它处理条件命令、循环和变量都在相同的插件中。对我来说,我目前选择postcss-simple-vars的原因是我喜欢单一原则,对于条件命令应该使用一个单独的插件来完成,拉下来我们会讨论postcss-conditionals插件。

当然,你也有可能不喜欢postcss-css-variables插件,而是更喜欢postcss-custom-properties插件。

两者之间的本质区别是:postcss-custom-properties严格按照W3C自定义属性规范,所以你只能相信,你写的是未来正确的CSS。另一方面,postcss-css-variables提供了额外的功能,但是这样做并不完全与规范相符。

我个人选择postcss-css-variables是因为我的上下文中使用它作为预处理,我不需要按照规范来编写代码。

另外,如果你使用上下文中的变量来写未来的CSS,你会发现postcss-custom-properties会更适合你。

添加each循环

each循环的插件

postcss-each插件安装到你的项目中,并且在_vars.css文件中添加下面的变量:

$social: twitter, facebook, youtube;

这行代码声明了一个列表,并且存储在$social变量中。

现在我们创建一个@each循环,用来遍历$social变量中的每个值。将下面的代码添加到src/style.css文件中:

@each $icon in ($social){    .icon-$(icon) {        background: url('img/$(icon).png');
    }}

@each循环已经创建好了,但在编译它之前,需要更改一下postcss-simple-vars的配置参数。

你会注意到,在上面的代码中使用了$icon来表示我们遍历的当前值。由于postcss-simple-vars插件会查找$,并且将其识别为变量。

这也意味着,它将会把$icon认为是一个变量,试图处理它,然而又没有找到其值。这个时候编译代码,控制台会停止编译,并且返回的错误日志,发现一个未定义的变量。

解决这个问题,我们要给插件设置一个参数silent: true。这意味着,如果它发现一个未定义的变量不会停止编译,而只是记录一个错误之后,将会继续编译。因此@each循环中的