CSS Modules 简单入门
CSS的选择器在全局范围都会生效,比如有时候会有A写了 btn
的class定义了一个默认显示蓝色按钮, B之后不小心也写了一个 btn
的class, 很不幸,A需要的按钮样式可能被B所写的样式覆盖! Bootstrap中的类似btn这种情况,在 btn
的class 通常定义的是所有按钮通用的样式,并且通过在定义 btn-success
、btn-error
等样式通过选择器优先级来实现不同的样式。但是这种依旧相当于在全局中定义了样式, 无法避免将来有人不经意的又写了btn-success
这样的class覆盖或者影响了之前的样式。
为了解决这问题,前端大牛们提出了种种的命名约定来避免命名冲突。 比如OOCSS、SMACSS、BEM、SUIT等等。 以BEM为例,class的名字以block__element--modifier
这种方式来命名,比如写个Menu, 那么Menu中的item处于active状态就要命名成 menu__item--active
这样的写法可能会解决问题,但是写起来总感觉有些反人类。所以有人说BEM很火,看着就想吐 . 并没有在项目中实践BEM这种命名方式,但是它来解决命名冲突的思路还是挺不错的,相当于通过模块命名前缀的方式避开在全局空间下命名,每个组件在它所属的命名空间下定义。
直到2014年Christopher Chedeau 在NationJS中所讲的CSS in JS, 前端衍生出两个流派,一个主张彻底抛弃CSS,在JS中来写样式,并且从中衍生出React Style、 jsxstyle、 Radium等实现。
CSS in JS 好处虽多,但是也有一些不便之处,比如无法使用css预处理器、调试困难、无法使用像PostCSS这样的CSS常用工具等。
在此基础上CSS Modules Team 提出的CSS Modules显的更加实用,我们还可以独立的写CSS文件,通过JS来管理样式依赖。
最近使用Mithril.js写了个小项目 并且尝试实践CSS Modules ,最终的效果如下:
文件结构
1 | +---components |
像写普通CSS一样写CSS文件,以Nav.css为例(CSS Modules 推荐驼峰式命名)
1 | .list { |
在JavaScript中引用css文件,并且定义元素的class。这里使用了Webpack,Browersify也可以实现。
1 | import m from 'mithril'; |
最终生成的效果如下:
其中生成的Class Name依赖于具体的配置规则,示例中的WebPack Loader配置如下:
1 | loaders: [ |
CSS文件里面的选择器通过在JS中import之后引用,Webpack会自动处理,这样我们就可以既避免BEM那种反人类的写法,又享受到模块化命名。
命名方式
CSS Modules推荐驼峰式命名,但是并不是强制的。需要注意的是在写样式的时候不推荐像Bootstrap那样通过选择器优先级来覆盖,一个Class应该包含该Class所有的样式,这样所有的组件、元素都是相对独立的。以btn的不同状态为例
1 | /* BootStrap是这样实现 */ |
CSS Modules组件里面Class命名不需要再加模块名的前缀,一般Webpack/Browserify配置好之后就能自动生成出来,类似BEM那样,模块名通常都以文件名来命名了。
Composition
上面说到一个Class应该包含它自身所需要的所有样式,但是并不意味着需要重复大量的代码, 用过Sass的应该比较熟悉@extend,在CSS Modules中也有类似的,叫Composition。
1 | .common {} /* 定义公用样式 */ |
如果使用了composes的话,必须在其它样式之前声明,composes也可以声明多个,使用 composes: commonA commonB
Global 范围的样式
有时候需要写一些全局范围的样式,比如经常使用的clearfix, CSS Modules提供了:global
1 | :global(.clearfix::after) { |
依赖管理
如果需要引入外部文件的样式也可以使用composes
1 | .default{ |
定义变量
如果使用了postcss和postcss-modules-values 就可以像Sass/Less一样使用变量
比如
fontsize.css1
2
3@value large: 2rem;
@value middle: 1.5rem;
@value small: 1rem;
Nav.css1
2
3
4
5
6@value fontsize: './fontsize.css';
@value large, middle, small from fontsize;
.list {
font-size: large;
}
总结
CSS Modules是目前实现CSS组件化最可行的方案之一,相对于其它实现,学习成本也会小很多,同时也能充分结合CSS生态工具(Sass/Less/Postcss等)和JS模块化能力。
本文作者 : Shuai Liang
原文链接 : http://liangshuai.me/2016/05/26/css-modules/
版权声明 : 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
知识 & 情怀 | 二者兼得