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循环中的$icon也就能编译成功。

gulpfile.jsgruntfile.js文件中的processors数组中,设置插件的option参数:

/* Gulpfile */
simple_vars({silent: true})

/* Gruntfile */
require('postcss-simple-vars')({silent: true})

编译之后的CSS:

.icon-twitter {
    background: url('img/twitter.png');
}

.icon-facebook {
    background: url('img/facebook.png');
}

.icon-youtube {
    background: url('img/youtube.png');
}

其它each循环插件

如前所述,postcss-advanced-variables是处理变量、循环和条件命令的一个很好的插件。

添加条件命令

条件命令插件的使用

在前面提到过,这个是我最喜欢用来处理条件命令的一个插件。主要因为它能够处理更为复杂的条件查询。它支持@else if语法,这意味着你可以在一段代码中测试更多的条件。

安装好postcss-conditionals插件之后,在src/style.css文件中添加下面这段测试代码进行测试。

$column_count: 3;

.column {
    @if $column_count == 3 {
        width: 33%;
        float: left;
    } @else if $column_count == 2 {
        width: 50%;
        float: left;
    }   @else {
        width: 100%;
    }
}

这段代码将会查询变量的值,根据$column_count变量不同的值输出widthfloat的值。只不过,现在我们可以使用@else if可以将条件数量从两个增加到三个(或更多个)。

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

.column {
    width: 33%;
    float: left
}

尝试着把$column_count改成21,然后重新编译,看看它是如何改变编译后的CSS。

我们也可以在混合宏中使用这些条件命令。例如,我们可以创建一个布局的混合宏:

@define-mixin columns $count {
    @if $count == 3 {
        width: 33%;
        float: left;
    } @else if $count == 2 {
        width: 50%;
        float: left;
    }   @else {
        width: 100%;
    }
}

.another_column {
    @mixin columns 2;
}

编译之后,输出的CSS:

.another_column {
    width: 50%;
    float: left;
}

其它的条件命令插件

如前所述,postcss-advanced-variables是处理变量、循环和条件命令的一个很好的插件。

添加calc()计算

calc()插件的使用

在前面的教程中,通过cssnano使用了postcss-calc插件,能更有效的帮助我们使用calc()。在预处理器中,帮助我们使用想要的数学表达式是非常有用的。

在你的项目中安装postcss-calc插件,在上面的布局混合宏示例中使用calc()将会更有效率。

在布局混合宏中设置一个$count参数,将参数设置为1,23,根据条件命令输出相应的预计算宽度。相反,使用calc(),不管混合宏中使用什么样的数字参数,都可以自动输出列的宽度值。

src/style.css文件中添加下面的测试代码:

@define-mixin columns_calc $count {
    width: calc( 100% / $count );
    @if $count > 1 {
        float: left;
    }
}

.column_calculated {
    @mixin columns_calc 2;
}

现在通过当前列数的数值计算出列的宽度来替代硬编码的百分比宽度。

postcss-calc插件,将根据参数$count值,通过width: calc(100% / $count)计算出列的宽度。在这个示例中,给混合宏中的$count值设置为2

编译之后,输出的CSS如下所示:

.column_calculated {
    width: 50%;
    float: left;
}

注意:postcss-calc可以在你的代码中输出静态的值,如果它不能,需要浏览器自己根据calc()进行动态计算。

添加嵌套

嵌套插件的使用

在PreCSS这个插件包中也使用了嵌套,所以在上一节的内容中你可以看到有关于嵌套语法的相关信息。

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

.menu {
  width: 100%;
    a {
        text-decoration: none;
    }
}

编译之后:

.menu {
    width: 100%;
}

.menu a {
    text-decoration: none;
}

添加扩展

扩展插件的使用

扩展我们将使用postcss-sass-extend插件。他的语法和前面介绍的PreCSS中的扩展语法有点不一样。将使用%extend_name {...}来替代@define-extend extend_name{...}声明代码块。

使用方法是基本上相同,使用的是@extend %extend_name来调用定义好的扩展代码块。

注意,postcss-sass-extend插件和PreCSS的扩展基本上是一样的,默认认情况之下,没有通过@extend调用声明好的扩展名,编译之后是不会加载任何代码。

将postcss-sass-extend插件安装到你的项目中,并且在src/style.css中添加下面的测试代码:

%rounded_button {
    border-radius: 0.5rem;
    padding: 1em;
    border-width: 0.0625rem;
    border-style: solid;
}

.blue_button {
    @extend %rounded_button;
    border-color: #2F74D1;
    background-color: #3B8EFF;
}

.red_button {
    @extend %rounded_button;
    border-color: #C41A1E;
    background-color: #FF2025;
}

编译之后的CSS:

.blue_button, .red_button {
    border-radius: 0.5rem;
    padding: 1em;
    border-width: 0.0625rem;
    border-style: solid;
}

.blue_button {
    border-color: #2F74D1;
    background-color: #3B8EFF;
}

.red_button {
    border-color: #C41A1E;
    background-color: #FF2025;
}

其他扩展插件

其他插件

到目前为止,有关于大多数预处理器的核心特性我们都覆盖到了。当然还有更多的插件可以提供一些其他的功能,其中一些功能和其他预处理器类似,而且你可以去PostCSS插件包中找到这些插件。现在简单介绍几款其他功能的插件。

处理颜色的插件

在预处理器中计算颜色是最有用的特性之一。PostCSS实际上有几个颜色的插件,但是这三个在预处理器中是最具特色的。它们可以根据颜色进行计算,比如变亮(lighten()),变暗(darken()),饱和度和透明度的值处理等等。

定义属性插件

这个插件提供的功能是可以无缝衔接Stylus中的混合宏,你不需要使用@mixin语法来定义代码块,你可以像这样的方式定义一个代码块,并且在代码中当作本地属性使用,如:

/* Define a property */
size: $size {
  height: $size;
  width: $size;
}

/* Use it like a native property */
.square {
  size: 50px;
}

这个插件也可以用来定义本地属性,来满足你的需求。

属性查询

属性查询的功能是Stylus中一个非常强大的特性。它允许你查找一个属性的值,并且传递给另一个属性。例如,你可以下面的代码一样,将margin-left的属性值传递给margin-right属性。

margin-left: 20px; 
margin-right: @margin-left;

属性嵌套

前面的内容介绍了选择器的嵌套,postcss-nested-props插件是用来实现属性嵌套,比如:

/* Origincal code */
.element {
    border: {
        width: 1px;
        style: solid;
        color: #ccc;
    }
}

/* After processing */
.element {
    border-width: 1px;
    border-style: solid;
    border-color: #ccc;
}

匹配插件

匹配是另一种条件查询插件,其语法有点类似于JavaScript或PHP中的swith语句。这样就可以设置类似于@if else 更多的条件。

生成CSS雪碧图

生成CSS雪碧图要属Compass最出名了,其实我们也可以使用postcss-sprites插件。这个插件会扫描你CSS中的图像,然后将这些图像合并成一张雪碧图,并且按照正确的显示位置重新更新你的代码。

更多的插件选择

目前有一个非常健全的语言扩展插件列表可供我们选择,你可以在这个列表中找到你想要的插件。

即将到来的其他语法

对于很多人来说,希望预处理器如上面说的Stylus或Sass,具有简洁的能力和有效的语法(通常是没有分号和花括号)。新发布的PostCSS V5.0版本就支持这种新语法的解析器。SugarSS就是一款简洁语法解析器。

你可以添加自己的插件

PostCSS相对而言还是较新的,你会发现你想实现的自定制预处理器的功能,目前还没有插件可支持。而PostCSS插件的良性生态系统,可以让你自己创建自己的插件来解决这个问题。任何人都可以做到,其门槛远低于Sass、Stylus或LESS中自定义函数的功能。在后面的教程中我们将学习如何自已开发一款自己需要的插件。

接下来的教程

你不需要选择PreCSS,你也可以根据自己的需求定制一款属于你自己的预处理器。你可以基于PostCSS的基础上选择你需要的功能插件,定制出你最喜欢的预处理器。

在接下来的教程中我们将学习如何使用PostCSS结合Stylus、Sass或LESS做更多你喜欢的事。

本文根据@Kezz Bracey的《PostCSS Deep Dive: Roll Your Own Preprocessor》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://webdesign.tutsplus.com/tutorials/postcss-deep-dive-roll-your-own-preprocessor--cms-24584

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。中国Drupal社区核心成员之一。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:http://www.w3cplus.com/PostCSS/postcss-deep-dive-roll-your-own-preprocessor.html

返回顶部