postcss 单独不转换_PostCSS-modules: 让CSS变得更强大

多年来,我们一直与全局CSS作斗争。现在是时候结束它了。不管你使用哪种语言或框架,CSS命名的冲突不再是问题。我将向你展示如何使用PostCSS和PostCSS-modules在服务端自动处理它。

CSS最初只是用来美化文档的一种工具。自1996年以来,许多事情发生了变化。浏览器不再是文档查看器了。聊天、工作、游戏,几乎没有任何浏览器不能做到的。

现在,我们比在HTML中标记文本和使用CSS开发内容的网站要多得多。我们使用CSS来充分发挥它的潜力,创造出它很难处理的东西。

每个经验丰富的软件开发人员都知道,你旦你使用了全局命名空间(Global namespaces),就相当于打开了一扇麻烦的大门。麻烦就很快的到来。如果在代码中没有为对象提供唯一的名称,那么你将不可避免地面临命名冲突、各种副作用以及无法维护的代码问题相继到来。

对于CSS来说,这意味着有布局的Bug,有CSS权重的烦恼,很长的选择器和无法调试的CSS。因为每个选择器都可以针对不需要的元素,并与其他选择器发生冲突。

几乎所有的编程语言都支持带有作用域隔离(Isolated scope)的模块。即使是一直与CSS密切相关的JavaSript,也具有AMD、CommonJS和ES6模块。然而CSS并没有这样的模块。

组件的隔离对于任何一个应用程序来说都是非常重要的。组件很小,很独立,可以使用它们作为砖块一样,让我们快速构建出更为复杂的应用。但我们还有一个问题:如果防止全局命名的冲突?

方法

因为我们的社区有很多有才华的人,让我们有了OOCSS、BEM、SMACSS和其他类似的方法。这些都是非常有用的方法。他们通过预先设置好的类来解决命名冲突的问题。

他们的主要问题是手工操作,我们必须自己编写这些很长的选择器。但你也可以使用处理器来处理,不过它只是消除效果,而不是原因。这个问题仍然存在。下面是我们如何使用BEM(对于其他方法,命名可能不同,查想法是相通的)来分离组件的示例:

/* 想要的CSS */

.article {

font-size: 16px;

}

.article__title {

font-size: 24px;

}

/* 使用处理器(SCSS) */

.article {

font-size: 16px;

&__title {

font-size: 24px;

}

}

CSS Modules

2015年有两种方法问世。一种是CSS-in-JS,另一种是CSS Modules。我们今天主要聊CSS Modules。

CSS Modules允许你自动处理所有的CSS类,默认情况这些类都是本地的(局部的),也是唯一的。然后生成一个JSON文件来存储原始类和映射出来的类。

/* post.css */

.article {

font-size: 16px;

}

.title {

font-weight: 24px;

}

上面的代码将被转换成像下面这样的代码:

.xkpka {

font-size: 16px;

}

.xkpkb {

font-size: 24px;

}

变换后的类将保存为一个JSON对象:

{

"article": "xkpka",

"title": "xkpkb"

}

在转换之后,你可以读取生成的JSON对象并使用它,而不是某些类:

import styles from './post.json';

class Post extends React.Component {

render() {

return (

);

}

}

如果想获得更多有关于这方面的知识,可以阅读这篇文章。

不仅保留了方法的优点,而且隔离的模块也被自动转换了。听起来让人难以置信,不是吗?

在这一点上,我们还有一个问题,我们只有在客户端使用CSS Modules的工具,但是在服务器端不使用Node.js,那就不容易了。至少目前为止是如此。

PostCSS-modules

为了在客户端和服务端都有CSS Modules,我编写了PostCSS-modules,一个PostCSS插件,在服务端Ruby、PHP、Python或任何其他语言中使用CSS Modules。

PostCSS是一个使用JS插件来编译CSS样式的处理器。这些插件可以检测你的CSS,也支持变量、混合宏、未来的CSS特性,内联图像等等。例如,Autoprefixer只是一个PostCSS插件。

如果你使用了Autoprefixer,那么表示你已经使用了PostCSS。因此,在插件列表中添加PostCSS-modules应该不是什么大问题。我将向你展示在Gulp和EJS中如何实现,但是你也可以使用其他任何语言来做同样的事情。

// Gulpfile.js

var gulp = require('gulp');

var postcss = require('gulp-postcss');

var cssModules = require('postcss-modules');

var ejs = require('gulp-ejs');

var path = require('path');

var fs = require('fs');

function getJSONFromCssModules(cssFileName, json) {

var cssName = path.basename(cssFileName, '.css');

var jsonFileName = path.resolve('./build', cssName + '.json');

fs.writeFileSync(jsonFileName, JSON.stringify(json));

}

function getClass(module, className) {

var moduleFileName = path.resolve('./build', module + '.json');

var classNames = fs.readFileSync(moduleFileName).toString();

return JSON.parse(classNames)[className];

}

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

return gulp.src('./css/post.css')

.pipe(postcss([

cssModules({ getJSON: getJSONFromCssModules }),

]))

.pipe(gulp.dest('./build'));

});

gulp.task('html', ['css'], function() {

return gulp.src('./html/index.ejs')

.pipe(ejs({ className: getClass }, { ext: '.html' }))

.pipe(gulp.dest('./build'));

});

gulp.task('default', ['html']);

然后,在命令终端运行gulp,执行Gulp中配置的任务,它会使用编译出来的CSS和JSON文件,并且在CSS中使用转换后的(JSON文件列表)类名。现在我们可以在EJS模板中使用生成的JSON文件中的值:

Title

...

如果你希望看到这段代码的作用,请在Github上查看这个例子。有关更多的使用示例,请参见PostCSS-modules在Github的示例和关于CSS Modules的文章。

有关于CSS Modules更多的教程,将会在这里不断的提供。另外在Github创建了一个有关于CSS Modules的仓库,将在这个仓库里整理各种环境和框架中使用CSS Modules的示例和工程化配置。

从没有感觉在编写可维护的CSS有这么容易过。不再需要庞大的混合宏,也不需要再写很长的前缀。同时也欢迎到未来的世界中。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值