深入PostCSS Web设计

本文节选自《深入PostCSS Web设计》一书,由电子工业出版社出版。

无论是美化 HTML 元素,还是创建复杂的页面动画,都离不开 CSS,CSS 是一个网站不可或缺的组成部分。如果一个网站没有使用 CSS 美化页面的样式,没有使用 JavaScript 响应用户的行为,那么这样的网页一定会失色不少。为网站开发精美的 CSS 样式往往会花费开发者大量的时间和精力,而开发者为了减少开发时间、避免重复工作,通常会选择预处理器自动化地构建 CSS 样式,比如为特殊属性添加浏览器前缀等。但是,使用预处理器的缺点也很明显,预处理器自身庞大且复杂,而开发者实际使用的功能却很少,也就是说预处理器被大材小用了。

PostCSS 的模块化风格就是为解决这一问题而诞生的,你可以使用它创建流式、快速的 CSS 处理器,而且没有一丝冗余的功能。在本文中,我们首先会介绍 PostCSS 的安装和使用方式,然后介绍 PostCSS 的架构模式,本文主要内容包含以下几个部分。

  • 思考为自己创建预处理器的优势所在。
  • 介绍 PostCSS 的基础知识和优秀特性。
  • 配置 PostCSS 的开发环境。
  • 创建一个使用 PostCSS 的示例。
  • 探索 PostCSS 的工作方式和架构模式。

下面就让我们开始吧!

本书所有的动手实践部分都是基于 Windows 系统进行设计和演示的,如果你使用的是其他操作系统,请根据你的实际开发环境进行适当的调整。

编译之美

问大家一个问题:Sass、Stylus、Haml 和 LESS,它们之间有哪些共同点呢?

答案是:它们都是将一种源码格式编译为另一种源码格式的编译器,官方术语称之为转换器(transpiler)。转换器的起源可以追溯到20世纪八十年代,在那一时期出现了很多不同格式的转换器,其中 Digital Reasearch 在 1981 开发的 XLT86 是最早的一代。

说完历史,我们再来看看近年来转换器的发展。众所周知的Sass预处理器诞生于 2006 年,Alexis Sellier 创建的 LESS诞生于 2009 年。它们的工作机制类似:接收一组样式并将其编译为原生的 CSS 代码。开发者可以直接使用它们提供的丰富功能,比如变量、混合宏(mixin)、函数等。这些转换器可能并不会减少开发者编写的代码数量,但可以帮助开发者以更可靠的方式管理代码,实现代码复用,进而提高代码的可维护性。

在使用这些预处理器时常常会遇到下列问题。

  • 使用这些预处理器前需要先安装一堆依赖,比如使用 Sass 前需要安装 Ruby;使用 LESS 前需要安装 JavaScript 相关的库。
  • 项目中往往只使用了预处理器极少数的功能,但开发者却被强制安装一个庞大的预处理器,比如 Sass。
  • 使用预处理器编译样式实际上是很慢的,虽然初始的编译过程只有几秒钟,但随着项目体量的增长,编译时间会越来越长。

由此看来,预处理器就不是那么迷人了。是否有一种方式或工具可以避免上述所有问题,并且还可以移除安装时的一堆依赖呢?

当然有,那就是让我们自己来创建一个样式处理器!当你第一次听别人这么说的时候,一定会觉得这很疯狂。不过不要担心我们的想法是天马行空,请听我详细解释一下为什么这是一个比预处理器更优秀的方案。

PostCSS介绍

上文提到了我们将会创建属于自己的预处理器,那我们到底要做什么呢?

实际上,我们在做一个预处理器的同时还会做一个后处理器。之所以这么做,是因为我们选择的工具允许我们同时创建这两个处理器,这个工具就是 PostCSS,你可以前往 https://github.com/postcss/postcss 下载它。目前,业界已经有公司将 PostCSS 应用到线上产品中,比如 Twitter、Google、Bootstrap、CodePen 以及 WordPress(限制性地使用部分功能)。

PostCSS 是一个基于 Node.js 构建的第三方模块,它可以与现有的大量 Node.js 插件同时运行。下面让我们花点时间探索一下使用 PostCSS 给前端开发带来的增益效果。

PostCSS的优势

当大家说到 PostCSS 时,到底是在指什么呢?简单来说,PostCSS 这个术语可以指代两件事:一是 PostCSS 核心工具,二是基于 PostCSS 创建的插件系统。PostCSS 核心工具并不能直接用于处理样式,只有配合它的插件,才能完成相关的编译工作。下面让我们看看在实际开发中如何使用 PostCSS。

  • PostCSS 的模块化架构意味着我们可以自由选择需要的插件,进而减少整个工具的体量,使整个工具保持轻量、可扩展。
  • 现有的处理器趋向于两种不同的类型:预处理器和后处理器,这限制了开发者的选择空间。而PostCSS 可以让开发者在一个处理流程中同时包含这两种操作,即编译前的预先处理和编译后的后置处理。也就是说,借助 PostCSS ,我们可以同时使用预处理器和后处理器,充分利用它们的优势进行开发工作。
  • PostCSS 可以无缝融合到现有的通用任务执行工具中,比如 Gulp、Grunt、Broccoli。通过这些工具, PostCSS 可以实现更广泛的自动化任务。
  • PostCSS 使用 JavaScript 编写而成,编译时无需添加其他依赖,不需要安装 Ruby、LibSass 之类的底层工具,其唯一的依赖是Node.js,大多数的前端工程师肯定已经安装过该工具了。
  • 无须再学习新的编程语言,前端工程师通常都能在工作中熟练使用 JavaScript 处理开发任务。
  • 可以根据需要随时添加或移除插件,这是其他大型工具无法实现的。
  • 开发门槛低,无论是按照自己的需求创建插件还是修改现有插件都很轻松。
  • PostCSS 的编译速度极快,下面的测试图片使用了 postcss-benchmark 插件(详见 https://github.com/postcss/benchmark),测试内容包括解析代码、嵌套规则、混合宏、设置变量和数学计算。显而易见,PostCSS 能轻松胜任。

深入PostCSS Web设计_第1张图片

  • PostCSS 本身是功能完备的,其不用像 Sass 一样考虑版本更新,不用考虑下载最新的 LibSass 等问题。

PostCSS的陷阱

使用自定义的处理器有一些注意事项,其中最重要的就是理解PostCSS 既不是预处理器,也不是后处理器,它更像是编译 CSS 的瑞士军刀。下面让我们看看使用 PostCSS 的一些潜在的陷阱。

  • 使用 PostCSS 虽然不需要学习新的编程语言,但还是会给我们的开发流程增加一定的复杂度。
  • PostCSS 的灵活性导致开发者可能会将其用作预处理器或后处理器,这种浅显的用法会让开发者无法真正掌握 PostCSS 的能力,开发者应该更积极地使用 PostCSS 去处理更多有关样式的问题。
  • 从使用现有的预处理器切换为使用 PostCSS 处理代码会有一定的困难,所以不要直接进行转换,应该渐进地转换到使用 PostCSS。
  • PostCSS 要求传入的 CSS 必须在语法上保持正确,否则编译时容易出错,即使是一行简单的注释都不容忽视。
  • 使用 PostCSS 的优势在于其可以与Gulp之类的任务处理工具无缝融合,并且不要求开发者必须使用 Gulp。
    如果你已经使用类似 Sass 的预处理器开发了网站,那么可以使用独立的工具编译代码,但通常来说,使用 Node.js 和 Gulp 是更好的处理方式。听起来还不错吧?那么该如何迁移到 PostCSS 的开发环境中呢?

很简单,我们可以从部分代码开始使用 PostCSS 进行编译。这里的关键是不使用 PostCSS 执行最初的编译,而是对编译后的 CSS 再次编译,比如添加浏览器前缀或压缩 CSS 代码等。一旦完成了这一步,就可以继续将 PostCSS 的其他插件融合到编译流程中,这些插件所包含的功能类似Sass 内置的功能。一旦现有的代码都转换成了插件所支持的格式,那么我们就可以彻底切换到使用 PostCSS 的编译环境了,也就可以放心地从项目中移除 Sass。

消除误解

在这里有必要花点时间回应业界对 PostCSS 的一些误解,虽然很多开发者将其视为预处理器或后处理器,但这并不是创建 PostCSS 的初衷。

  • 将 PostCSS 视为后处理器,或者将其视作与预处理器相反的处理,都是一种误解。PostCSS 有能力应对不同的使用场景,它既可以处理已经被预处理器编译过的代码,也可以处理纯粹的 CSS 代码。
  • PostCSS 不应该被当作一个处理某个流程的工具,比如处理 Sass 循环或条件语句的工具。在 PostCSS 中有大量的插件可以处理这些事情,但这些功能不足以概述 PostCSS 的全貌,PostCSS可以在开发者的开发工作流中处理更多的任务。
  • 如果你发现某些时候 PostCSS 所编译的结果不符合预期,那么很有可能是使用的插件出现了问题,而不是 PostCSS 本身出现了问题。虽然 PostCSS 这个项目还很年轻,但其生态中已经有了大量的插件,非常值得一试。
    前面的预热已经很完美了,接下来让我们少说多做,用实际代码演示 PostCSS 的安装和使用方法。

准备工作

在开始之前,我们需要一些准备工作。第一,需要一个本地的 Web 服务器,虽然这并不是必备的,但这有助于提升学习效果。就我个人而言,我喜欢使用 WAMP 服务器(适用于 PC,从http://www.wampserver.com/en获取);对于使用 Mac 的用户来说,可以尝试使用 MAMP(从http://www.mamp.info/en获取);如果不喜欢上面两个,还可以使用跨平台的 Apache Web 服务器(从http://www.apachefriends.org获取)。无论使用上述哪一个服务器,它们的默认配置都足以满足我们的开发需求。

第二,需要在本地创建一个项目目录。假设你已经搭建了 WAMP 作为本地 Web 服务器,那么就可以在 c:\wamp\www 文件夹下创建一个名为 postcss 的文件夹,如下图所示。

深入PostCSS Web设计_第2张图片

完成上面的准备工作后,就让我们开始安装 PostCSS 吧!

搭建开发环境

学习 PostCSS 的第一步是使用 Node.js 工具安装它。通常我们会使用某种任务执行工具来做这件事。对于本文中的所有练习,我们都使用 Gulp 作为任务执行工具。当然,你也可以根据自己的喜好选择 Grunt 或 Broccoli。

当使用 Node.js 时,请确保使用的是 Node.js 的命令提示符窗口,而不是 node.exe,使用 node.exe 不能完美地运行本文的示例代码。
接下来,让我们安装Node.js 和 Gulp。

第一步:安装 Node.js。通过 http://nodejs.org 可以获取适合各种操作系统的安装包,下载适合你的操作系统的安装包之后,就可以开始安装了。

深入PostCSS Web设计_第3张图片

安装 Node.js 时,接受默认配置即可,这足够我们用来演示本书中的代码了。

第二步:打开 Node.js 命令提示符窗口并输入以下命令,输入完成后按回车键执行。

node -v

输出结果就是所安装的 Node.js 的版本信息,这是一种快速检查 Node.js是否正确安装的方法。
图片描述

第三步:正确安装Node.js以后,还需要创建一个 package.json文件描述项目中所用到的依赖信息。在命令提示符窗口中输入以下命令,输入完成后按回车键执行。

npm init

第四步:创建 package.json 时,Node.js 会在命令提示符窗口向开发者提出一些问题,开发者可以参考下图中的回答,也可以按回车键选择默认配置(每个问题的默认配置信息会使用中括号进行标注)。

深入PostCSS Web设计_第4张图片

现在我们已经安装好了 Node.js,并在项目中创建了一个空的 package.json 文件。接下来我们添加第三方依赖,第一个需要添加的是 Gulp。

第一步:回到 Node.js 命令提示符窗口(如果已经关闭了之前的命令提示符窗口,那么你需要新建一个)。

第二步:在命令提示符窗口中将当前的工作路径切换到 c:\wamp\www\postcss。

第三步:在命令提示符窗口中输入以下命令,输入完成后按回车键执行,该命令将会在全局环境中安装 Gulp。


npm install -global gulp

第四步:安装完成后,需要将 Gulp 安装到项目中。在命令提示符窗口中输入以下命令,输入完成后按回车键执行。该命令将安装Gulp到当前项目的同时,还会更新package.json 的配置信息。

npm install --save-dev

安装完成后,Gulp 就可以直接使用了。接下来我们要在 Node.js 和 Gulp 的基础上安装 PostCSS。

使用 –save-dev 的小提示:这一参数用于指定开发阶段所需要的第三方依赖,如果是线上产品所需要的第三方依赖,可以使用 –save 进行安装。

安装 PostCSS

现在就到了最有趣的步骤——安装 PostCSS。从 https://github.com/postcss/postcss 可以查看 PostCSS 的项目信息,我们可以通过一个 Gulp 插件将其安装到 Node.js 的开发环境中,让我们开始吧!

第一步:回到 Node.js 命令提示符窗口(如果已经关闭了之前的命令提示符窗口,那么你需要新建一个)。

第二步:在命令提示符窗口中输入以下命令,输入完成后按回车键执行。

npm install --save-dev gulp-postcss

如果一切顺利,我们将会看到下图所示的信息。

深入PostCSS Web设计_第5张图片

只安装 PostCSS 并不能处理任何任务,为了让它变得更加实用,我们将会安装三个插件。大家可以在《深入 PostCSS Web设计》书中查看详细介绍使用插件的方式,这里先做个简单的演示。各位不用太关心安装过程发生了什么神秘的事情。

第一步:在命令提示符窗口中输入以下命令,输入完成后按回车键执行。

npm install --save-dev autoprefixer

第二步:让我们看一下 package.json 文件,如果一切顺利,我们将会看到下图所示的信息。

深入PostCSS Web设计_第6张图片

为了在 Sublime Text 中方便地查看 JSON 文件,建议安装并使用第三方主题,比如 MonokaiJSON Plus(https://github.com/Colibri Apps/MonokaiJsonPlus)。

PostCSS 现在已经安装完成,但还不能直接使用它,我们还需要为它编写配置文件。接下来我们将通过一个简单的示例来演示如何为它编写配置文件,在这个示例中会为 CSS 代码添加浏览器前缀并对最终生成的代码进行压缩。

使用PostCSS创建一个简单的示例

PostCSS 是一个迷人的工具,它的模块化架构使其可以驾驭多种使用场景,甚至是多种场景叠加的复合场景。在《深入PostCSS Web设计》一书中,我们将会演示 PostCSS 在多种场景下的使用方式,并最终实现在同一套工作流下创建包含预处理器和后处理器的处理器。

为了让大家了解 PostCSS 的工作方式,我们在这里创建了一个简单的处理器。它会为CSS 属性自动添加浏览器前缀,并自动压缩最终生成的代码。

在上文中,我们已经安装了相关插件,下面就让我们来动手创建一个 Gulp 配置文件。

第一步:新建一个文件并添加下图中的代码,完成后将其保存在项目的根目录下,并命名为 gulpfile.js。

深入PostCSS Web设计_第7张图片

第二步:在项目的根目录下创建一个名为 dest 的文件夹,实际上该文件夹会在编译过程中自动创建。

第三步:新建一个文件,添加以下代码,完成后将其保存在根目录下的 src 文件夹中,并命名为 example.css。

body {
    display: flex;
    background: green;
}

第四步:回到命令提示符窗口并输入如下命令,输入完成后按回车键执行。

gulp styles

通过上面的命令,Gulp 将会自动执行 gulpfile.js 中的指令。

图9

第五步:等待几秒钟,我们就能在项目根目录下的 dest 文件夹中看到编译之后的 example.css。

第六步:在编辑器中打开编译后的 example.css, 查看编译后的代码,如果一切顺利,将会看到下图所示的内容。

深入PostCSS Web设计_第8张图片

完美!PostCSS 已经安装完成了,当我们需要添加浏览器前缀时,运行我们的工作流工具即可。

添加 Source Map 功能

这就是 PostCSS 吗?是,但不是全部,PostCSS 能够胜任的工作远不止添加浏览器前缀!还记得我们之前说过 PostCSS 常常被误用为预处理器或后处理器吗?

使用 PostCSS 的一大好处就是可以有选择性地对代码进行处理,且不需要安装额外的依赖,最终我们创建的处理器会非常轻巧和快速。在上一个示例中,我们创建了一个名为 styles 的任务,接下来我们将会使用任务名为 default 的任务代替它执行相关任务,使用 default 任务便于我们通过一条命令执行多个任务。这意味着执行 gulp 命令即可完成多个任务,无需再指定特定的命令名。

在接下来的练习示例中默认使用这种方式调用和执行 Gulp 任务。

让我们开始扩展之前的编译流程吧。这里我们使用 Florian Reiterer 开发的 Source Map 插件(从https://github.com/floridoo/gulp-sourcemaps获取)来添加Source Map支持。

第一步:打开命令提示符窗口,并切换工作区到项目根目录下。

第二步:输入以下命令,输入完成后按回车键执行。

npm install --save-dev gulp-sourcemaps

第三步:打开“使用 PostCSS创建一个简单的示例”小节中创建的 Gulp 配置文件,然后添加 gulp-sourcemaps 插件,代码如下。

var autoprefixer = require('autoprefixer'); 
var sourcemaps = require('gulp-sourcemaps');

第四步:添加一行命令用于生成 Source Map(还是在这个文件之中),代码如下。

.pipe(postcss([ autoprefixer ]))
.pipe(sourcemaps.init())
.pipe(sourcemaps.write('maps/'))
.pipe(gulp.dest('dest/'));

第五步:保存上述文件内容,然后在命令提示符窗口中输入以下命令,输入完成后按回车键执行。

gulp styles

第六步:如果一切顺利,在 dest 文件夹下可以找到一个名为 maps 的目录,该文件夹下存储着 Source Map 文件。

通过在编译流程中自动生成 Source Map 文件,我们向创建更强有力的开发工具迈出了重要的一步。

注意:如果在本书中看到“项目目录”这样的描述或引用,那么它指的就是当前项目的根目录。

我们可以做的还有很多。虽然这里生成的 CSS 体积很小,但仍然应该对其进行压缩以避免浪费不必要的带宽。使用 PostCSS 可以轻松胜任压缩任务,下面就让我们来看一下如何使用 cssnano 插件压缩 CSS 代码。

压缩样式

压缩样式是样式开发过程中的重要组成部分,其应该是每个开发者工作流中必备的流程。压缩样式可以有效减少对带宽的占用,这一流程对小型网站的收益可能并不是很明显,但对大型网站的影响则是显著的。

使用 PostCSS 压缩样式是轻而易举的事情。在接下来的教程中,我们将会使用 cssnano(从http://cssnano.co/获取)和 gulp rename(从https://github.com/hparra/gulp- rename获取)两个插件实现压缩样式的功能,插件的安装和使用方式如下。

第一步:打开命令提示符窗口,输入以下命令,每行输入完成后按回车键执行。

npm install -–save-dev cssnano
npm install -–save-dev gulp-rename

执行完成后不要关闭命令提示符窗口,稍后我们还会继续使用它。

第二步:切换到之前创建的 gulpfile.js 文件,并将以下代码添加到文件的最后一个 } 之后,} 大概在第12行。

gulp.task('rename', ['styles'], function () { 
    return gulp.src('dest/example.css') 
        .pipe(postcss([ cssnano ])) 
        .pipe(rename('example.min.css')) 
        .pipe(gulp.dest("dest/")); 
});

gulp.task('default', ['styles', 'rename']);

第三步:在 gulpfile.js 的顶部添加两条声明,否则我们的代码将会报错。具体的声明代码如下。

var sourcemaps = require('gulp-sourcemaps');
var rename = require('gulp-rename');
var cssnano = require('cssnano');

第四步:细心的读者会发现 gulpfile.js 现在存在问题:在文件的最后我们引用了 styles 这个任务,但还没有对其进行声明和编写。解决这个问题的方法很简单,那就是将第8行的代码修改为如下内容。

gulp.task('styles', function() {

第五步:保存文件并切换回命令提示符窗口,输入如下命令,输入完成后按回车键执行。

gulp

第六步:Gulp 的编译结果如下图所示。

深入PostCSS Web设计_第9张图片

如果一切顺利,可以在项目文件夹下的 dest 文件夹中看到下图所示的文件。

深入PostCSS Web设计_第10张图片

在项目的根目录下,不仅包含 Source Map 的 maps 文件夹,现在还增加了一个经 cssnano 压缩后的样式文件,该样式文件经过压缩以后还会经 rename 插件重命名。

不幸的是,我们现在还存在一个问题,如果查看maps 文件夹的内容,会发现 Source Map 所针对的是未压缩版本的样式文件,而不是压缩版本的样式文件。为了解决这个问题,需要在 gulpfile.js 中添加如下内容。

.pipe(rename('example.min.css'))
.pipe(sourcemaps.init())
.pipe(sourcemaps.write('maps/'))
.pipe(gulp.dest("dest/"));

现在再尝试运行 Gulp,如果一切顺利,就会发现已经有了针对压缩版本样式的 Source Map,如下图所示。

深入PostCSS Web设计_第11张图片

让我们继续完成 Gulp 的配置文件吧。目前还剩下最后一步:添加 watch 功能,以便于在文件内容发生变化后自动执行编译流程。

自动化编译

使用 Gulp 添加 watch 功能非常简单,添加 watch 功能之后人力工作会大量减少,只需启动一次 Gulp 任务,即可持续监视并处理内容发生变化的文件。

与其他功能不同的是,使用 Gulp 的 watch 功能无须添加任何插件,只需将下面的代码添加到 gulpfile.js 文件中即可。

gulp.task('default', ['styles', 'rename', 'sourcemaps']);

var watcher = gulp.watch('src/*.css', ['default']); 
watcher.on('change', function(event) { 
    console.log('File ' + event.path + ' was ' + event.type + ', 
        running tasks...'); 
});

添加完上述代码以后, gulpfile.js 文件的全貌应该如下图所示。

深入PostCSS Web设计_第12张图片

对比无误后就可以保存 Gulp 的配置文件,并像之前一样重新运行 gulp 命令了。现在运行 gulp 命令之后,Gulp 会监视 src 文件夹下的文件变动并自动执行编译。在配置文件中,我们为日志信息添加了一个事件处理器,用于输出编译信息,读者可以根据自己的需要修改这段代码。

现在已经有了一个初级的构建工具,在本书接下来的几章中,我们将会继续向这个工具添加功能,直至创建一个属于我们自己的处理器。接下来我们还需要了解一个小功能,虽然它并不是必要的,但是对开发样式很有帮助,它就是代码审查功能,用于保障代码的有效性。

代码审查

毫无疑问,代码审查应该存在于所有开发者的工作流中。实现代码审查有多种方式,使用哪种方式主要取决于你所使用的构建工具。使用 PostCSS 实现代码审查非常简单,只需要安装配套的审查插件到上面实现的处理器中即可,在这里我们使用 stylelint 插件(从http://stylelint.io/获取)来实现。

为什么要做代码审查?简单来说,是为了保持代码风格的一致性。当你参与团队开发时,代码审查的作用会愈加明显,其核心作用是约束团队中每个成员的代码风格,保证编译结果的一致性。将代码审查功能添加到工作流中,有助于减少人力工作,实现任何时间、任何人的代码的编译结果具有一致性。

从这一目标出发,让我们看看如何实现代码审查功能。

第一步:打开命令提示符窗口,并切换工作区到项目的根目录下。

第二步:在命令提示符窗口中输入以下命令,输入完成后按回车键执行。

npm install stylelint

如果一切顺利,将会看到下图所示的输出结果。

深入PostCSS Web设计_第13张图片

第三步:安装postcss-reporter插件(从https://github.com/ postcss/ postcss-reporter获取),它可以向命令提示符窗口或屏幕输出 stylelint 代码审查的结果,如下图所示。

深入PostCSS Web设计_第14张图片

第四步:安装完上述插件之后,需要更新 Gulp 的配置文件 gulpfile.js,将如下代码添加到该文件声明变量的位置。

var cssnano = require('cssnano'); 
var stylelint = require('stylelint'); 
var reporter = require('postcss-reporter');

第五步:在上述的代码后面添加下面这段代码。这段代码增加了一个新的 Gulp 任务,用于执行代码审查功能,并在适当的时候通知开发者错误信息。

gulp.task("lint-styles", function() { 
    return gulp.src("src/*.css") 
        .pipe(postcss([ stylelint({ 
            "rules": { 
                "color-no-invalid-hex": 2, 
                "declaration-colon-space-before": [2, "never"], 
                "indentation": [2, 2], 
                "number-leading-zero": [2, "always"] 
            } 
        }), 
        reporter({
            clearMessages: true, 
        }) 
    ])) 
});

编写完上述代码后,需要将 gulpfile.js 中的如下代码。

gulp.task('default', ['styles', 'rename']);

修改为如下代码。

gulp.task('default', ['lint-styles', 'styles', 'rename']);

第六步:修改项目根目录下的 src 文件夹中的 example.css 文件,修改其中的一个 color 的值为 #fff1az。

第七步:回到命令提示符窗口,输入以下命令,输入完成后按回车键执行。

gulp

第八步:用Gulp 解析我们的现有代码,应该会抛出一个下图所示的提醒。

深入PostCSS Web设计_第15张图片

从命令提示符窗口中可以得到明确的反馈:#fff1az 不是一个有效的数值!stylelint 之所以会提示这个问题,是因为我们在配置中规定了相关的规则。

.pipe(postcss([ stylelint({
    "rules": {
        "color-no-invalid-hex": true,
        …
    }
}),

让我们花点时间了解一下这个插件是如何工作的,该插件的核心是 stylelint 提供的一组代码审查的规则(详见 https://cdn.rawgit.com/stylelint/stylelint/1.0.0/docs/rules.md),开发者从中选取需要的规则写入gulpfile.js 中,这样每次运行 Gulp 任务时就会通知 stylelint 检查这些规则,比如 -no-invalid-hex 规则。我们可以为 stylelint 添加任意数量的规则,最终实现输出结果的一致性。

如果你对这些规则的工作机制感兴趣,可以阅读 https://cdn.rawgit. com/stylelint/stylelint/1.0.0/docs/user-guide.md,更多有关stylelint的使用示例可以查看 https://cdn.rawgit.com/stylelint/stylelint/1.0.0/ docs/rules.md。

接下来让我们深入了解一下 PostCSS 的工作机制,然后聊一聊如何从 Sass 的开发环境迁移到 PostCSS 的开发环境。

PostCSS 工作机制

我们已经讲解了配置和使用 PostCSS 的基础知识,接下来有必要花时间了解一下 PostCSS 的工作机制,这有助于我们更好地理解如何使用 PostCSS,也有助于我们开发自己的 PostCSS 插件。

PostCSS 本身并不处理任何具体的任务,只有当我们为其附加各种插件之后,它才具有实用性。

PostCSS 就像是一个使能器(enabler),它不用完全替代现有的预处理器或后处理器,而只是作为它们的补充工具。PostCSS 的工作机制主要包含解析代码、执行插件、渲染结果三部分,如下图所示。

深入PostCSS Web设计_第16张图片

PostCSS 会将 CSS 代码解析成包含一系列节点的抽象语法树(AST,Abstract Syntax Tree)。树上的每一个节点都是 CSS 代码中某个属性的符号化表示。换言之,如果你写了条件语句并对应三种结果,那么在抽象语法树中就会有一个包含三个分支的节点,每个分支就是符号化表示的结果。

感兴趣的读者可以查看AST的一个示例http://jointjs.com/demos/ javascript-ast,这个示例演示了如何使用纯JavaScript来分解一个简单的算术函数。

编译后的抽象语法树会被传递给后续的插件做进一步处理,在被插件处理生成最终的 CSS 之前,样式代码实际上是一段冗长的字符串。基于这些特性,我们可以创建自己的插件,相关的插件模板和 API 可以从 PostCSS 在 GitHub 的主页获取。

在插件处理阶段,我们需要做好的一项工作是使用符合业务需求的插件,坚持单一职责原则。实际上,如果一个插件所能承担的任务越多,那么它的使用效果会越不理想,因为它很有可能在项目中承载了过多不会被使用到的功能,造成职责不清晰。

从 Sass 迁移到 PostCSS

假设我们要使用 PostCSS 进行开发,那么面临的首要问题就是:如何从现有的开发环境迁移到 PostCSS 的开发环境呢?

我们最好不要直接将现有代码迁移到 PostCSS 开发环境,因为这很有可能会出现问题。我们应该将现有代码逐步切换到 PostCSS 的开发环境中,从容易实现的地方开始使用 PostCSS。创建 PostCSS 开发环境需要做不少工作,但不必担心,下面会介绍一些技巧帮助读者规避迁移过程中的陷阱。

迁移的核心是理清 PostCSS 开发环境切实需要的功能,然后为它创建一个初始化的构建流程(可以使用 Gulp 或 Grunt),然后逐步根据需求往流程中添加插件,直至实现完整的编译器。

在上面的基础上,我们可以更进一步,使用插件让 PostCSS 解析 Sass 风格的代码。Autoprefixer插件可以作为我们使用的第一个插件,接下来可以添加 postcss-mixins插件和 postcss-partial-import插件。在本书第11章中我们将会使用这些插件模仿 Sass 语法,并最终替代类似 Sass 或 LESS 的预处理器。在 JavaScript 的生态环境中,这一切都切实可行且易于操作。

PostCSS 中用于模仿 Sass 语法的插件已经被打包在了 PreCSS 包中,我们将会在本书第10章对此做详细介绍。

在本书接下来的几章中,我们将会学习创建样式编译器所需要具备的基本要素,比如变量、混合宏等,也将会学习如何在 Sass 或 LESS 中使用它们,然后使用 PostCSS 的相关插件实现相同的功能,生成最终的 CSS 代码。最终,我们的目标是将所有的插件集成为一个属于自己的样式处理器。

小结

CSS 开发是与互联网同时兴起的技能,创建一个精美的 CSS 样式需要高超的技能、坚持不懈的耐心,并投入大量的时间。类似 Sass 和 LESS 的预处理器可以帮助开发者更高效地处理样式,但仍然存在某些缺陷。PostCSS 则为开发者提供了一个定制化的编译方式,同时消除了现有处理器的历史包袱。在本文中,我们已经了解了 PostCSS 的一些核心概念,接下来让我们回顾一下这些概念。

在介绍 PostCSS 之前,我们首先了解了编译的历史,然后介绍了使用 PostCSS 的优势和难点,以及它是怎样无缝融入开发工作流的。

在讲解 PostCSS 的安装方式时,我们还介绍了如何将 PostCSS 融入Gulp 构建工具中,之后使用一个实际案例演示了 PostCSS 的编译过程,讲解了如何选择合适的插件,如何摆脱重复的人力工作。在代码编译工作中,我们还添加了 watch 功能、代码审查功能,从而确保编译的一致性。

最后,我们介绍了 PostCSS 的工作机制、组织架构,进一步了解了如何从纯 CSS 或使用预处理器的开发环境迁移到使用 PostCSS 的开发环境。

现在我们已经对 PostCSS 颇为熟悉了,是时候在项目中真正地使用它了。

点击购买《深入PostCSS Web设计》:

深入PostCSS Web设计_第17张图片

欢迎加入“CSDN前端开发者”群,与更多专家、技术同行进行热点、难点技术交流。请扫描以下二维码申请入群。
图片描述

你可能感兴趣的:(PostCSS)