PostCSS-modules: 让CSS变得更强大

发布于 大漠

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

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

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

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

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

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

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

方法

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

他们的主要问题是手工操作,我们必须自己编写这些很长的选择器。但你也可以使用处理器来处理,不过它只是消除效果,而不是原因。这个问题仍然存在。下面是我们如何使用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 (
            <div className={ styles.article }>
                <div className={ styles.title }>…</div>
                …
            </div>
        );
    }
}

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

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

在这一点上,我们还有一个问题,我们只有在客户端使用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应该不是什么大问题。我将向你展示在GulpEJS中如何实现,但是你也可以使用其他任何语言来做同样的事情。

// 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文件中的值:

<article class="<%= className('post', 'article') %>">
    <h1 class="<%= className('post', 'title') %>">Title</h1>
    ...
</article>

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

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

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

本文根据@evilmartians的《PostCSS-modules:make CSS great again!》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://evilmartians.com/chronicles/postcss-modules-make-css-great-again

大漠

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

如需转载,烦请注明出处:https://www.fedev.cn/css/postcss-modules-make-css-great-again.htmlnike air max 2019 style