PostCSS基本介绍

@kvkens 2017-06-03 02:36:20发表于 iuap-design/blog

PostCSS基本介绍

PostCSS 处理了很多你不必处理的乏味工作。它很巧妙的不同于预处理器,提供了可选的且更简洁的编程语言,来编译成 CSS,如 Sass、Less 与 Stylus。得出这个结论的部分原因是:

  • PostCSS 既能在预处理器将源代码编译成 CSS 之前也能在其之后对文件执行操作
  • PostCSS 能替代你的预处理器。现在有很多插件实现了一些设计,如变量、 嵌套、mixins 以及 extends。

CSS 预处理器 和 CSS 后处理器

在说 PostCSS 之前,先了解一下 pre-processor 。

pre-processor(预处理器)

在写CSS的时候,经常会碰到这样的问题,比如说“变量”:

h1{
    color:red;
}
.title{
    color:red;
}
.classA{
    color:red;
}

如果有一天,我想要把颜色改用蓝色怎么办?你需要:查找 -> red ->替换 -> blue 。

先这种简单的 CSS 中,可能这并不繁琐,但是对于大型应用来说,可能是要摔键盘了。还有更多的问题,比如代码复用,嵌套,Mixins(混入)等等…

于是 Sass / Less就出现了,他们都是 CSS 的预处理器(pre-processor),看个简单的范例:

$font-stack: Helvetica, sans-serif;
$primary-color: #333;
 
body {
  font: 100% $font-stack;
  color: $primary-color;
}

这里用了变量功能,以后想要修改 CSS 直接改变量内容就好,不用在每一个地方都改了。像 Sass 这些预处理器,你要学一些新的语法,学一些新的表示方式,你就可以用这些新的语法写好一些看起来很像 CSS 但不是 CSS 的东西,然后把它编译成 CSS 。

post-processor(后处理器)

了解什么是 pre-processor 以后,来看看什么是 post-processor 。

post-processor(后处理器)最常见的例子就是这个了 CSS Prefixer 。

在写 CSS 的时候,会针对浏览器加上一些前缀,但是每次都这样写实在是很麻烦,官方范例,原本 CSS 是这样的:

.my-class, #my-id {
    border-radius: 1em;
    transition: all 1s ease;
    box-shadow: #123456 0 0 10px;
}

使用 CSS Prefixer 添加前缀后:

.my-class, #my-id {
    -moz-border-radius: 1em;
    -webkit-border-radius: 1em;
    border-radius: 1em;
    -moz-transition: all 1s ease;
    -o-transition: all 1s ease;
    -webkit-transition: all 1s ease;
    transition: all 1s ease;
    -moz-box-shadow: #123456 0 0 10px;
    -webkit-box-shadow: #123456 0 0 10px;
    box-shadow: #123456 0 0 10px
    }

而 CSS 再经过后处理器 ( post-processor ),透过一些规则帮它加上一些东西,最后产出完整的CSS文件!

或许你有一个疑问,预处理器( pre-processor )不是也可以完成这种工作吗?

确实,在 Sass 里面,用 mixin 也可以达成加上前缀这样的目的。

那为什么要用 post-processor ?

后处理器有几个优点:

  1. 你可以写自己的插件:如果你选了 Sass ,你就必须接受 Sass 的一切,接受他的语法,要用就要用一整套 Sass,你不能只选择你要的某些功能,但是如果你用了 PostCSS ,你可以选择你自己想要的功能。更加确切的说,平时工作你基本不会直接去使用 PostCSS ,它的功能基本都是插件去完成的。 PostCSS 只是提供了一个环境。举例来说,加上前缀就是一个功能,或是让你可以用变量也是一个功能,你可以自己选择你想要的功能加入,而不是一用就要用一整套完整的方案,当然,你也可以用javascript写自己的plugin,解析 CSS 语法并且加入一些自己想要的东西。

  2. 用标准的 CSS 语法:前面有提过预处理器跟后处理器的差别,一个是写好 Sass(或其他的)丢进去,一个是把 CSS 加上一些东西之类丢出来,有些人相信将来的某一天,所有浏览器都会支援标准的 CSS ,例如说你不必再加上 -webkit- 之类的prefix
    到了那一天,如果你是用 PostCSS ,你可以不做任何动作,直接拿原有的 CSS 就好,但如果你用的是 Sass 就没有办法这样
    像是http://www.myth.io/ 这套,就提倡用「未来的 CSS 标准」写 CSS ,在现代先用后处理器的方式去产生可以跑的 CSS ,但是在未来的某一天,把那些 plugin 去除以后,你的 CSS 还是可以正常地跑出结果。

PostCSS 介绍

PostCSS 本身是一个功能比较单一的工具。它提供了一种方式用 JavaScript 代码来处理 CSS。它负责把 CSS 代码解析成抽象语法树结构(Abstract Syntax Tree,AST),再交由插件来进行处理。插件基于 CSS 代码的 AST 所能进行的操作是多种多样的,比如可以支持变量和混入(mixin),增加浏览器相关的声明前缀,或是把使用将来的 CSS 规范的样式规则转译(transpile)成当前的 CSS 规范支持的格式。从这个角度来说,PostCSS 的强大之处在于其不断发展的插件体系。目前 PostCSS 已经有 200 多个功能各异的插件。开发人员也可以根据项目的需要,开发出自己的 PostCSS 插件。

PostCSS 从其诞生之时就带来了社区对其类别划分的争议。这主要是由于其名称中的 post,很容易让人联想到 PostCSS 是用来做 CSS 后处理(post-processor)的,从而与已有的 CSS 预处理(pre-processor)语言,如 SASS 和 LESS 等进行类比。实际上,PostCSS 的主要功能只有两个:第一个就是前面提到的把 CSS 解析成 JavaScript 可以操作的 AST,第二个就是调用插件来处理 AST 并得到结果。因此,不能简单的把 PostCSS 归类成 CSS 预处理或后处理工具。PostCSS 所能执行的任务非常多,同时涵盖了传统意义上的预处理和后处理。PostCSS 是一个全新的工具,给前端开发人员带来了不一样的处理 CSS 的方式。

使用 PostCSS

PostCSS 一般不单独使用,而是与已有的构建工具进行集成。PostCSS 与主流的构建工具,如 Webpack、Grunt 和 Gulp 都可以进行集成。完成集成之后,选择满足功能需求的 PostCSS 插件并进行配置。下面将具体介绍如何在 Webpack、Grunt 和 Gulp 中使用 PostCSS 的 Autoprefixer 插件。

Gulp

为了在 Gulp 中使用 PostCSS,你需要建立你的项目并安装两个模块:

npm init -y
npm install --save-dev gulp gulp-postcss

然后,你可以继续添加你需要的插件,如: autoprefixer 与 cssnano。

npm install --save-dev autoprefixer cssnano

你可以创建一个 gulpfile.js 文件。它定义了一个任务,加载 CSS 源文件然后通过 PostCSS 管道。插件以及任意所需的其它选项以一个数组传给 PostCSS。最终,CSS 文件被输出至目标文件。

// Gulp.js 配置
var gulp = require('gulp'),
    postcss = require('gulp-postcss');
 
// 应用 PostCSS 插件
gulp.task('css', function() {
  return gulp.src('src/main.css')
    .pipe(postcss([
      require('autoprefixer')({}),
      require('cssnano')
    ]))
    .pipe(gulp.dest('dest/main.css'));
});

在控制台,可使用下面的命令运行该任务:

gulp css

现在我们只差一份方便的 PostCSS 插件列表了

Webpack

Webpack 中使用 postcss-loader 来执行插件处理。在代码清单 1 中,postcss-loader 用来对.css 文件进行处理,并添加在 style-loader 和 css-loader 之后。通过一个额外的 postcss 方法来返回所需要使用的 PostCSS 插件。require(‘autoprefixer’) 的作用是加载 Autoprefixer 插件。

var path = require('path');
 
module.exports = {
 context: path.join(__dirname, 'app'),
 entry: './app',
 output: {
   path: path.join(__dirname, 'dist'),
   filename: 'bundle.js'
 },
 module: {
   loaders: [
     {
       test:   /\.css$/,
       loader: "style-loader!css-loader!postcss-loader"
     }
   ]
 },
 postcss: function () {
   return [require('autoprefixer')];
 }
}

Grunt

Grunt 中使用 grunt-postcss 来集成 PostCSS。Grunt 中需要使用 grunt.loadNpmTasks 方法来加载插件,如代码清单 3 所示。

module.exports = function(grunt) {
 grunt.initConfig({
   postcss: {
     options: {
       processors: [
         require('autoprefixer')()
       ]
     },
     dist: {
       src: 'app/**/*.css',
       expand: true,
       dest: 'dist'
     }
   }
 });
  grunt.loadNpmTasks('grunt-postcss');
}

后面会介绍常用的PostCSS插件