PostCSS 简介

Krystal 9年前

PostCSS 简介

CSS 的开发和所有编程语言一样,是一个迭代的过程。每一次主版本的发布都为我们带来新的功能和语法,让我们更好的编写样式。CSS 3 支持交互,这之前只能通过 Javascript 来实现。每天都会有新的工具让我们更简单、更灵活的实现样式。

PostCSS 就是最近被推荐的一个样式处理工具。PostCSS 旨在通过自定义的插件和工具生态体系来重新定义 CSS。与类似 Sass 和 LESS 这样的预处理机制类似,它可以把扩展的语法和功能转换成现代的浏览器友好的 CSS 代码。

How you ask? JavaScript.

JavaScript 能做到比其他处理方式更快的转换我们的样式。通过 Gulp 或 者Grunt 这样的 task-runner 工具,我们可以在 build 过程中对样式进行转换,这与 Sass 和 LESS 的编译过程非常类似。React 和 AngularJS 这样的库和框架还允许我们在 JavaScript 中直接编写 CSS 代码,这为使用 JavaScript 来转换样式打开了一扇大门。

PostCSS 的历史

PostCSS 是 Autoprefixer 的开发者 Andrey Sitnik 开发的,最初是一个通过 JavaScript 来处理 CSS 的方法。PostCSS 本身只是一个 API,不过加上庞大的插件生态体系,作用就非常强大了。为了提供有用的调试功能,PostCSS 还生成了源码的 map,而且还提供了抽象语法树(AST)来帮助我们理解代码是如何被转换的。

PostCSS 使用的是 Node.js 框架,编程语言和工具的能力使得对 PostCSS 的修改和自定义都很简单。Sass 和 LESS 则受限于编译器自身锁提供的能力。

作为一个 API,PostCSS 让我们能够创建任何需要的插件和工具。这种模块化的平台设计使得这个工具比较专一,更专注于功能需求。PostCSS 对语言格式不做限制,如果需要也可以使用 Sass 和 LESS 的语法格式。

模块化的好处

大部分开发者都不是完全从头开始一个项目的。不少人会使用一个 Sass 模板项目,包含了一些变量、mixin 和函数。我们将使用单独的样式文件包含那些函数、mixin、网格体系和通用的工具,这样可以让开发更轻松一些。最终我们会有 10 个或更多的样式文件把一切都组织起来。

维护一个 Sass 或 LESS 代码片段的库是非常繁琐的,也会让项目变得非常臃肿。很多项目都有未使用的 mixin 和函数,包括那些“以防万一”的很少使用的代码。PostCSS 支持易安装、即插即用的模块,这对于那些需要特定功能的项目来说,开发过程变得非常灵活。

PostCSS 把项目中所有需要创建函数、工具和 mixin 的代码提取出来封装成插件。这样,对于每一个项目,我们都可以在项目里通过包含插件的方式来引入需要的功能。

这种优势的一个例子是 PostCSS FontPath 插件。用 Sass 时,我们不能在文件中包含 mixin 来支持 web 字体,所以不得不创建一个 @font-face 标签。

@mixin importfont($font-family, $font-filename, $font-weight : normal, $font-style :normal, $font-stretch : normal) {    @font-face {      font-family: '#{$font-family}';      src: url('#{$font-filename}.eot');      src: url('#{$font-filename}.woff') format('woff'),    url('#{$font-filename}.ttf') format('truetype');      font-weight: $font-weight;      font-style: $font-style;      font-stretch: $font-stretch;    }}@include importfont('mission script', 'fonts/mission-script-webfont', 300);

如果在项目中使用 PostCSS FontPath 插件,我们就不用像上面这样包含 Sass mixin。我们只需要在 CSS 里写下面的代码,PostCSS 会通过 Grunt 或 Gulp 转换成我们需要的代码。

@font-face {    font-family: 'My Font';    font-path: '/path/to/font/file';    font-weight: normal;    font-style: normal;}

写这篇文章的时候,社区里有超过 100 个插件,涉及未来的 CSS 语法、快捷方式、工具、语言扩展等等。它不仅仅是一个工具,从使用的用户量来说,可以比得上 WordPress、Google 和 推ter。

工作流中加入 PostCSS

PostCSS 是用 JavaScript 写的,我们可以在代码里用 Gulp 或者 Grunt 这样的任务管理器来转换 CSS。下面的教程演示了如何在项目中使用 Gulp 或 Grunt 的工作流中与 PostCSS进行协作。两者之间具体选择哪个并不重要,取决于个人喜好以及是否适合项目。

注意:工具的 Gulp 和 Grunt 版本的列表在 GitHub 上。你可以任选一个作为起始模板,然后安装自己需要进行扩展。

在 Gulp 里配置 PostCSS

如果你对 Gulp 不太熟悉,建议你先阅读一下 Callum Macrae 的使用 Gulp 进行构建”来了解和运行这个工具。

在终端运行这个命令可以在项目里安装 PostCSS 模块:npm i gulp-postcss -D.

在项目的 Gulpfile.js 文件里,我们需要包含已安装的 PostCSS 模块,然后在任务里使用它。你需要更改其中的路径,包括开发代码路径和转换输出文件的目录。

var postcss = require('gulp-postcss');gulp.task('styles', function () {      return gulp.src('path/to/dev/style.css')          .pipe(postcss([]))          .pipe(gulp.dest(path/to/prod))});

在命令行运行 gulp styles 可以运行任务。

在 Grunt 里配置 PostCSS

注意:如果你对 Grunt 不太熟悉,推荐阅读 Mike Cunsolo 的“Grunt 入门和实践”,可以让你对这个工具更了解一些。

在终端运行这个命令可以在项目里安装 PostCSS 模块:npm i grunt-postcss -D.

插件安装完成之后,在 Gruntfile 文件里将其启用,然后按下面的方式创建一个任务。你需要根据你项目的目录结构,更新其中的 cwd 和 dest 变量。

module.exports = function(grunt) {    grunt.initConfig({      pkg: grunt.file.readJSON('package.json'),      styles: {        options: {          processors: []        },        dist: {          files: [{            expand: true,            cwd: 'dev/',            src: ['**/*.css'],            dest: 'prod/'          }]        }      }    });      // Load post-css.  grunt.loadNpmTasks('grunt-postcss');};

在命令行执行 grunt styles 运行这个任务。

安装插件

PostCSS 自身并不强大;它的强大来自它的插件。也许你已经发现之前 Gulp 和 Grunt 的实现当中,任务说明中的数组是空的。这些数组可以定义我们打算 import 的社区开发的 PostCSS 插件,也就是我们需要包含的那些功能。

PostCSS 的 GitHub 页面可以找到那些验证过的插件列表,跟 NPM 的包一样,这些插件也都可以通过命令行安装。很多插件只能作为 PostCSS 的扩展,而不能直接在你所用的 task runner 中使用。例如,我们安装插件 PostCSS Focus 后,会给 hover 增加一个 a:focus 状态。

接下来的例子里,我们都会使用命令行用 NPM 在我们的项目里安装包。

PostCSS 插件安装示例 链接

npm i postcss-focus -D

插件可以直接作为方法的参数,不过为了代码清晰,我们可以构造一个数组,然后把插件放到数组里作为参数。在数组里,我们可以包含所有需要的 require 语句,这些 require 语句会返回插件,然后被立即调用。如果你需要对此有更多的了解,可以看一下 Ryan Christiani 的Javascript 中函数作为一等公民”。

require('postcss-focus')()

对于 Grunt,修改后的代码如下(包含我们刚创建的 processorArray 数组):

var processorArray = [      require('postcss-plugin')()];// Snipped for brevitystyles: {        options: {          processors: processorArray      },        dist: {          src: 'path/to/dev/style.css',          dest: 'path/to/prod/style.css'        }      }

下面是 Gulp 的版本:

var processorArray = [      require('postcss-plugin')()];gulp.task('styles', function () {      gulp.src('path/to/dev/style.css')          .pipe(postcss(processorArray))          .pipe(gulp.dest('path/to/prod'))});

插件

安装好插件,build 工具也可以编译我们的代码后,我们就可以开始使用 PostCSS 及其插件的功能了。首先要做的是在开发目录下创建一个 .css 为后缀的文件。

“什么!一个 CSS 文件?” 每错,就是一个 CSS 文件。因为 PostCSS 会帮我们转换 CSS,所以我们不需要特殊的语法,只需要使用传统的 CSS。如果你对预处理的机制比较熟悉,你可能会觉得有些不自然,因为我们隐藏了.sass、.scss、.styl 或 .less 文件,又回到了 .css 文件。不过实事是,这并非是改换,而是一种转换。

为了处理我们刚安装的 PostCSS 插件的样式,我们可以分别安照 grunt 和 gulp 的样式去运行 task runner。CSS 文件将被 PostCSS 以及相应的插件处理,输出结果会保存到指定的输出目录。

下面是一些对你会有帮助的插件的介绍,包含了插件的安装指导和使用说明。

Autoprefixer

编写能适用于数量众多的浏览器版本和不同的设备是一件痛苦的事情,要记得哪些属性需要加哪些前缀就更是一个挑战。幸运的是,Autoprefixer 可以告诉我们什么时候、在哪里需要添加这些浏览器厂商的前缀。这个插件让我们只需要关注如何使用最新的功能和属性来编写样式,而不用关系这些属性针对不同的浏览器需要添加哪些前缀。

命令行安装这个插件的方式:

npm i autoprefixer -D

当我们把这个插件加到我们的数组里后,可以提供一个对象,这个对象包含了项目需要支持的浏览器的数组。可用的选项列表可以在这里找到:Browserslist Github Account

下面我们就把 Autoprefixer 插件加到 processor 中:

var processorsArray = [    // snipped for brevity  require('autoprefixer')({ browsers: ['last 2 versions', 'ie 6-8', 'Firefox > 20']  })];

根据这里提供的浏览器支持列表,相应的浏览器厂商前缀会加到对应的 CSS 属性和值上。

这是我们的 CSS 代码:

.item {    display: flex;    flex-flow: row wrap;}

转换后的输出是这样的:

.item {    display: -webkit-flex;    display: -ms-flexbox;    display: -webkit-box;    display: flex;    -webkit-flex-flow: row wrap;        -ms-flex-flow: row wrap;            flex-flow: row wrap;}

通过 CSSNext 来使用未来的语法

CSS4 很快就会到来,它会带来一些新的特性,包括本地变量自定义媒体查询自定义的选择器 和新的pseudo-links。虽然写本文的时候 CSS4 还没有被所有浏览器支持,不过它被批准后肯定会被最新的浏览器支持的。

CSSNext 可以把所有 CSS4 特性转换成浏览器可以识别的 CSS3 代码。这个工具可以单独使用,也可以作为 PostCSS 的一个插件。我们可以将其加到 processorsArray,这个数组包含了其他的 PostCSS 插件。

通过命令行安装 CSSNext 插件

npm i cssnext -D

然后,添加插件到你的处理器

var processorsArray = [    // snipped for brevity  require('cssnext')()];

现在,在产品代码中,你可以写 CSS4 特性,以及 PostCSS 将通过任务运行器转换语义,从而支持今日的浏览器。当浏览器来支持新语义时,你可以通过开发 CSS 来替换转换的输出。

在这里开发 CSS:

// Custom Variables  :root {    --linkColour: purple;}a {    color: var(--linkColour);}// Custom media queries with ranges@custom-media --only-medium-screen (width >;= 500px) and (width <= 1200px);@media (--only-medium-screen) {    /* Medium viewport styles */}// Custom selectors@custom-selector :--enter :hover, :focus;@custom-selector :--input input, .input, .inputField;    a:--enter {    /* Enter styles go here */}:--input {    /* Input field styles go here */}

这里是转换后的输出:

a {    color: purple;}@media (min-width:500px) and (max-width:1200px){    body{      background:#00f;    }}a:focus,a:hover{    background:#00f;}.input, .inputField, input{    background:red;}

如果你想探索更多的 CSSNext 特性,该网站有一个游乐场,你可以尝试使用当前 CSSNext-supported 的 CSS4 特性。

SaaS 语法

如果 Sass 是你首选预处理的程序语言,别害怕:你可以通过 PostCSS 来使用其语法与工具。然而传统的 CSS 还不支持诸如 PreCSS 允许我们使用这些特性和在传统的 CSS 文件中写 SaaS 语法的变量,嵌套和进口插件。

如果我们在我们的数组中通过命令行和参考包来添加插件到我们的构建,我们可以立即在 Sass 语法中开始编写。如果你从 Sass 切换到 PostCSS,你可以改变文件扩展到 .css 以及通过任务运行器来输送。

通过命令行来安装 PreCSS 插件,像这样:

npm i precss -D

然后,添加插件到你的处理器:

var processorsArray = [    // snipped for brevity  require('precss')()];

此外,在这里开发 CSS:

/*Variables*/$blue: #0000ff;$green: #00ff00;$radius: 10px;.square {    background: $blue;    border-radius: $radius;}/*Imports*/@import "partials/_base.css";/*Mixins*/@define-mixin square $dimension {      width: $dimension;      height: $dimension;}/*Nesting, variables and mixins*/.button {    @mixin square 200px;    background: $green;    &:hover {      background: $blue;    }}

然后转换输出:

.square {    background: #0000ff;    border-radius: 10px;}.button {    width: 200px;    height: 200px;    background: #00ff00;}.button:hover {    background: #0000ff;}

使用社区插件扩展 CSS

虽然插件可用于帮助我们更有效地编写代码,但是 PostCSS 的重心在于社区插件。这些插件给我们更快的方式编写风格,或者至少更容易的方法来实现创造性的样式。使用这些插件的 PostCSS API,它允许在我们的项目中自定义属性,选择器和价值观,使我们能够更有效地和使用更少的搜索来编写样式。

量查询

量查询是强大的。他们允许我们计算元素的 CSS 和基于他们同胞数量之上的应用样式。虽然选择器有点难写,因为他们使用一些先进的 CSS 选择器,今天您可以在你的 CSS 中使用它们。虽然像 QQ 在线工具的存在是为了帮助我们写这些查询,我们可以直接的利用 PostCSS 来使用自定义选择器的样式。

通过使用量查询,以及在像任何其他的项目中安装插件,通过命令行:

npm i postcss-quantity-queries -D

并将插件添加到你的处理器:

var processors = [    // Snipped for brevity  require('postcss-quantity-queries')()];

一旦安装,您可以使用自定义选择器,仅仅可用于基于匹配的元素应用样式来通过其插件。

在这里开发 CSS:

// To apply styles if 'at least' number of sibling elements present  .container > .item:at-least(5) {    background: blue;}    // To apply styles if 'at most' number of sibling elements present  .item > a:at-most(10) {    color: green;}    // To apply styles if number of sibling items 'between' a range is present  .gallery > img:between(4, 7) {    width: 25%;}    // To apply styles if 'exactly' number of provided items is present  .profiles:exactly(4) {    flex: 1 0 50%;}

 然后转换输出:

// To apply styles if 'at least' number of sibling elements present  .container > .item:nth-last-child(n+5), .container > .item:nth-last-child(n+5) ~ .item {    background: blue;}    // To apply styles if 'at most' number of sibling elements present  .item > a:nth-last-child(-n+10):first-child, .item > a:nth-last-child(-n+10):first-child ~ a {    color: green;}    // To apply styles if number of sibling items 'between' a range is present  .gallery > img:nth-last-child(n+4):nth-last-child(-n+7):first-child, .gallery > img:nth-last-child(n+4):nth-last-child(-n+7):first-child ~ img {    width: 25%;}    // To apply styles if 'exactly' number of provided items is present  .profiles:nth-last-child(4):first-child, .profiles:nth-last-child(4):first-child ~ .profiles {        flex: 1 0 50%;}

通过 Short 扩展 Shorthand Properties

当我们编写样式时,您可能会遇到让你说,“这可能是更短的。“的语法属性。 该 Short 插件帮助我们做到那一点:更符合逻辑地编写我们的样式。它使我们编写 shorthand properties forpositionandsize,就像 howbackgroundandfontcan 能用一个简单的声明。

通过该 PostCSS API,该 shorthand 声明被转换为允许一个清洁发展样式表和一个更有组织的生产样式表的 browser-digestible 风格。

通过命令行安装 Short 插件:

npm i postcss-short -D

添加插件到你的处理器:

var processors = [    require('postcss-short')()];

该 text 属性包括这些输入属性:color, font-style,font-variant, font-weight, font-stretch, text-decoration, text-align,text-rendering, text-transform, white-space, font-size, line-height,letter-spacing, word-spacing and font-family.

在这里开发 CSS:

p {    text: 300 uppercase dimgrey center 1.6rem 1.7 .05em;}

然后转换输出:

p {    color: dimgrey;    font-weight: 300;    text-align: center;    text-transform: uppercase;    font-size: 25px;    font-size: 1.6rem;    line-height: 1.7;    letter-spacing: .05em;}

该声明中的 position 属性允许包括 top, left, right, bottom 值。该值的顺序是顺时针方向的,在语法中使用 1 到 4 的值。如果有一个在其位置中你愿意排除和仅仅通过一个*的值。

在这里开发 CSS,然后:

section {    position: absolute 10px * *;}.topNav {    position: fixed 0 * * 0;}.modal {    position: fixed 40% 25%;}

然后转换输出:

section {    position: absolute;    top: 10px;}.topNav {    position: fixed;    top: 0;    left: 0;}.modal {    position: fixed;    top: 40%;    right: 25%;    bottom: 40%;    left: 25%;}

这对我们的行业意味着什么?

目前使用 PostCSS 是完全可能收获到好处的。就像我们编译 Sass 和 LESS 的过程,你可以通过修改任务运行组件去处理 PostCss,以此把 PostCSS 整合到你的工作流程中。在你现有的 Sass 工程中合并一个像 PreCSS 这样的插件,就可以移植到 PostCSS,你连语法都不用转换。

就在本文的写作的同时,一场关于哪里是写 CSS 的最佳位置的讨论正在进行。随着 React 等库的流行,在组件内部写样式的想法势头正猛,它允许我们将样式与 JavaScript 直接编译。虽然这还知识是一个讨论,但是这的确是一种与使用 PostCSS 进行改动样式的方案。

另一个在业界引起轰动的项目是 CSS 模块,它把样式包含在本地文件中,按需使用。这个概念已经 JavaScript 圈子里流行。并且随着 React 和 JSX等前端语言之间的界限越来越模糊,CSS 和 JavaScript 的联合力量变得难以忽视。

当 PostCSS 用新的方式自定义语法和特性来继承 CSS 的时候,它可能会给那些试着掌握这种语言和它的复杂性的初学者带来挑战。如果你和一个中级开发者使用 PostCSS 开发一个项目,尽量鼓励他们去深入理解这门语言,像 Sass 一样,PostCSS 是一个简单的制作工具,它使编写样式变得高效。

今天就使用 PostCSS

在接下来的几年里,我们使用 CSS 的方式将会有许多的改变。每一个项目都有不同的需求,我们需要适应我们的生产方法。使用像 PostCSS 这样的模块化生态系统能让我们选择和使用我们所需要的特征去完成项目。

我希望你去探索 PostCSS 的世界以及它里面所有可用的插件。因为它是一个社区项目,只有当人们使用它、给它制作插件才会使这个生态系统成长。想要探索更多的插件,可以浏览 NPM 上的可用包,并且测试它们的性能在 PostCSS Playground上。

(rb, al, ml)