PostCSS深入学习: PreCSS的使用

在《PostCSS深入学习: 跨浏览器兼容性》和《PostCSS深入学习: 压缩和优化CSS》两篇文章中学习了使用PostCSS插件实现跨浏览器的兼容性和CSS样式的压缩与优化,本质上说,这些都是后处理CSS的方式。在这篇教程中,你将学习PostCSS插件中的预处理插件包PreCSS,可以像使用Stylus,Sass或LESS一样使用PreCSS

使用PreCSS主要有两种方式。第一种是选择你自己需要的预处理器功能插件进行安装,另一种就是安装整个PreCSS插件包。

在这篇教程中我们使用最快和最容易的方法,安装@Jonathan Neal提供的整个PreCSS插件包。在后面的内容中,我们再学习如何整合自己的预处理器,这个预处理器只有自己想要的功能。

在开始后面的教程之前,我假设对类似Sass、LESS或Stylus这样的预处理器常见特性有一定的了解。主要原因是,在这里我们将关注的是如何使用PostCSS实现类似的功能,而不是去做这些功能。话说,就算你从未了解过任何CSS预处理器,那么这或许对你来说也是一个完美的开始。

尝试使用PreCSS

在接下来的内容,会详细介绍如何在你的项目中使用Gulp或Grunt来设置PreCSS,然而,你可能现在就想看到PreCSS编译CSS的代码效果,你可以点击这个DEMO,看到PreCSS编译CSS前后的代码。窗口左边是PreCSS语法编写的代码,窗口右边是编译后的CSS代码,而且你可以在左边输入PreCSS代码,右边就能正确显示编译后的CSS代码。

PreCSS的使用

PreCSS在线编辑器

设置您的项目

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

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

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

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

安装PreCSS

不管你是使用Gulp还是Grunt,都可以使用下面的命令来安装PreCSS:

npm install precss --save-dev

使用Gulp加载插件

如果你使用的是Gulp,可以在gulpfile.js中添加下面的变量:

var precss = require('precss');

并且在processors数组中添加变量名:

var processors = [
    precss
];

通过gulp css命令可以做一个快速测试,你可以看到你项目中dest文件夹中添加style.css文件。

使用Grunt加载插件

如果你使用的是Grunt设置项目,可以在你的gruntfile.js文件中的processors对象中添加下面的变量名,并且给指定对应的options参数:

processors: [  require('precss')()
]

在命令终端执行grunt postcss命令做一个快速测试。查看你项目的dest文件夹中是否添加了style.css文件。

现在你已安装好PreCSS了。这也意味着,接下来我们可以开始了解PreCSS有哪些预处理的功能与特性,又该如何使用它们。

PreCSS预处理器

简单说,PreCSS语法和Sass是最相似的。然而,PreCSS也有一些自己独特的方法,接下来我们会介绍。

注意:因为PreCSS和Sass语法极其类似,你可以选择一个支持Sass语法高亮的编辑器来编写PreCSS代码。

嵌套

三大主流预处理器,比如Sass、LESS和Stylus中都具有嵌套特性,在PreCSS中也有。PreCSS中的嵌套同Sass或LESS中的实现方法一样,都是通过在选择器的大括号内嵌套选择器。

PreCSS和其的预处理器一样,可以使用&符,把父选择器复制到子选择器中。

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

.menu {    width: 100%;
    a {
        text-decoration: none;
    }
    &::before {        content: '';
    }
}

使用gulp css或者grunt postcss编译你的CSS,在dest/style.css文件中你可以看到嵌套编译出来的代码像下面这样:

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

变量

PreCSS和其他预处理器一样,都具有变量这种特性。只不过每个处理器之前声明变量的语法规则是不同的:

  • LESS中使用@符声明变量,比如@color: #ccc;
  • Stylus中使用$符声明变量,比如$color=#ccc;
  • Sass中使用$符声明变量,比如$color: #ccc;

在PreCSS中保持了类似Sass声明变量的语法,在$符号后面紧跟变量名,然后变量名后面有冒号:,其后再是变量值。如:

$color: #ccc;

你可以在src/style.css文件中添加变量:

$text_color: #232323;body {    color: $text_color;}

编译之后,你就能看到下面这样的代码:

body {    color: #232323;}

条件

在Sass和Stylus中提供了类似于ifelse这样的条件命令,但在LESS中提供了guarded mixins功能,可它们不具备完全相同的功能。在PreCSS中也有条件命令这样的特性,其语法和Sass的相同,也是使用@if@else

src/style.css文件中添加下面这段示例代码:

$column_layout: 2;

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

在上面的示例代码中,我们有一个column类,但根据不同的条件输是一列布局或两列布局。其中设置了一个变量$column_layout,并且给其赋值2。意思是,当$column_layout等于2的时候,实现的是两例布局,此时.column的样式是width: 50%;float:left;,否则是单列布局,这时.column样式是width: 100%;

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

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

注意:postcss-advanced-variables插件提供的条件命令功能还是很新的,当使用一些复杂的条件命令时,会遇到一些意想不到的输出。但我始终相信,不久的将来这方面将会得到改善。

有关于条件命令还可以使用postcss-conditionals插件。接下来的教程中将讨论如何使用自己选择的插件,这样你就可以大声的说,这是属于我自己的预处理器

循环:@for@each

在PreCSS中有两种循环:@for@each。这两种循环的使用方法和Sass的一样。@for循环通过一个数字计数器完成一个循环周期;@each循环可以用来遍历一个项目列表。

@for循环

@for循环中有一个计数器变量,用来设置循环的周期,通常设置为$i。例如,从13表示有三个循环迭代,第一个$i等于1,第二个等于2,第三个等于3

可以在选择器或样式规则中插入这个变量$i,这样可以非常方便的生成像nth-of-type()的选择器和计算宽度。

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

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

编译之后,你可以看到计算后的结果:

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 );}

注:数字1,23插入到上面的样式代码中。

@each循环

@each循环中,它的一个循环周期是一个项目列表而不是数字。和@for循环一样,可以列表的当前项填充到选择器和样式规则中。注意:插入到一个字符串中你需要使用一组括号包裹一个变量名(如($var))

给PreCSS的@each循环添加一个测试用例,代码如下:

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

编译之后,就会生成这样的CSS代码:

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

混合宏(Mixins)

PreCSS中的混合宏语法和Sass的有点不同。

在Sass中是通过@mixin mixin_name($arg1,$arg2){...}这样的语法来声明一个混合宏,然后使用@include mixin_name(pass_arg1,pass_arg2)来调用声明好的混合宏。

在PreCSS中,使用了另一个声明方式,使用@define-mixin mixin_name $arg1, $arg2 {...}来声明一个混合宏,然后使用@mixin mixin_name pass_arg1, pass_arg2;来调用声明好的混合宏。

src/style.css中添加下面的代码:

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

编译之后,你可以看到下面这样的CSS:

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

注意:混合宏参数可以像上面介绍的@each循环一样,使用一组括号括起参数,如($var),会将参数当作字符串插入到选择器中。

使用@mixin-content

上面我们介绍了PreCSS中的混合宏怎么使用,除了可以传递参数之外,还可以传递内容。这个过程和Sass中的@content本质是相同的。

例如,修改上例中的混合宏,将你想要传递的内容块通过@mixin-content传递进去,如下所示:

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

使用混合宏中的@mixin-content必须得放在一个花括号{}中,而不是在结束一行的;后面,不然编译有可能会无法进行。

像下面的代码一样,重新更新你的混合代码:

@mixin icon twitter, blue {    width: 3rem;
}@mixin icon youtube, red {    width: 4rem;
}

编译之后,将生成下面的所示的代码,注意宽度使用混合宏的方式已添加进去了:

.button.twitter {    background-image: url('img/twitter.png');
    background-color: blue;
    width: 3rem;}.button.youtube {    background-image: url('img/youtube.png');
    background-color: red;
    width: 4rem;}

扩展

在某种意义上扩展类似于混合宏,他们旨在让你复用重用的代码块。然而,扩展的想法是创建一个多次复用的代码块。

在PreCSS中使用@define-extend extend_name{...}方式来声明扩展的代码块。

src/style.css文件中定义了一个按钮基本样式的代码块:

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

这个默认风格还可以添加其他的样式代码,比如