css 算是前端发展的一个痛点吧. 以前是裸写css, 接着到后来的 inline css, 然后是, scss/sass. 从单一 file 到可以模块化书写css. 不过, 随着前端发展, 现在的要求是组件化, 那么, 以前那种直接 < link> 脚本也逐渐变为痛点. so, 2015/6 左右, 出来了 css-module 这个概念. 可以说, 这是一个专门为 component 编程而生的. 因为,他是和 js 紧密结合在一起的.
css-module 更具官方的说法就是: css-module 其实就是原来的 css 文件。只是他的 className 和 animation 最后都会被编译为 object 形式的映射对象.
举个简单的例子就是:
// 未编译前的 style.css
.title {
background-color: red;
}
// 通过js 脚本调用
import styles from "./styles.css";
element.innerHTML =
`<h1 class="${styles.title}">
demo
</h1>`;
// 最后实际输出为:
# css 格式
._styles__title_309571057 {
background-color: red;
}
# HTML 格式
<h1 class="_styles__title_309571057">
demo
</h1>
上面简单的介绍了, css-module 到底是啥?
Ps: 上面漏了一点, 怎么将css 编译嘞? 这里,方法很多,有webpack, gulp等等. 看同学们自己的选择了
命名方式
首先,在 css-module 里面. 以前在 css 中的命名方式,都变得 nonsense. 在 css-module 推荐一切命名方式使用 camelCase 的形式. 因为, 在写组件的时候我们并不是来写全局的样式, 我们仅仅只是来完成我们当前组件的渲染. 所以, 这就要求, 这些组件所需和隐藏的 css 属性, 我们必须一个不拉的全部写上去, 比如: display, font, text-align 等等.
// 写一个 btn 的样式
# 原始的css
.btn-normal{...}
# 使用 css-module
# 实际该文件的保存名就是 btn-style.css
.normal{...}
.clickStyle{...}
组合 composition
既然, 上文已经说了 css-module 里面每个 style 都必须全部写出所需的样式, 那么, 这样重复的工作实在太多的... 谁 TM 还和你来什么 module 不 module 的. 所以, 为了解决这样的痛点, css-module 提供了 composes 这个概念. 相当于, 就是我们以前 css 中的嵌套.
// 原始 css
# 直接嵌套
.button{...}
.button .normal{...}
// 在 css-module 中
# 使用 composes 进行嵌套
.button{...}
.normal{
composes:button;
...
}
这个 composes 概念,就有点和 sass 中的 @extends 类似. 但,他俩编译的结果点都不像. composes 是直接在 DOM 渲染时, 添加不同的 class. 而 @extends 只是将 class 变为嵌套而已.
// @extends 语法
.Button--common { ... }
.Button--normal {
@extends .Button--common;
...
}
// 编译结果
.Button--common, .Button--normal {...}
.Button--normal {...}
但,这样并不符合 css-module 实际编译后改变 className 的 feature, 并且, @extends 的结果, 会造成很大的 className 冗余.
具体说一下 css-module composes 的过程.
// 正常书写 css-module
.common { ...}
.normal { composes: common; ... }
// 经过编译得出
# 注意,这里并没有存在嵌套的情况,每个className 都是分离的.
.components_submit_button__common__abc5436 { ... }
.components_submit_button__normal__def6547 { ... }
// 通过 import 的 css 暴露的接口为:
styles: {
common: "components_submit_button__common__abc5436",
normal: "components_submit_button__common__abc5436 components_submit_button__normal__def6547",
}
// 渲染出来的HTML DOM 节点内容
# 添加 style.normal 样式
<button class="components_submit_button__common__abc5436
components_submit_button__normal__def6547">
Submit
</button>
当然, composes 也可以引入其他 css 文件中的某个 class.
// colors.css
.primary {
color: #720;
}
// button.css
.normal {
composes: primary from "../shared/colors.css";
}
另外, 写好一个 css-module 有很多原则可以遵循的. 最出名的应该就是 单一职责原则.
单一职责
因为 composes 的限制, 我们一般只能引入单一的 className 去包裹我们想要的 style 样式. 但这样,感觉有点浪费. 这点,感觉 sass 做的还是挺棒的.
@mixin subtle-shadow {
box-shadow: 0 0 4px -2px;
}
// 直接通过 mixin 引进
.some_element {
@include subtle-shadow;
}
所以, 为了在 css-module 达到同样的目的. 我们一般只能使用单一的文件去包裹,所需的样式内容. 像下面的 demo:
// 直接从其他文件中引进
.element {
composes: large from "./typography.css";
}
具体实例
css-module 主要是和 react 一起使用. 因为, react 存在, 才使前端组件化得到蓬勃的发展. so, 我们这里,就需要借助 webpack 对 import 的 css 文件进行编译.
这里就不多说了, 直接把配置放出来吧.
// 引入所需的插件
var ExtractTextPlugin = require('extract-text-webpack-plugin');
# 下面就是具体的 module.exports 里面的内容
module: {
// 关键语句. 处理 css-module的内容.
loaders: [
{ test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader') }
]
},
postcss: [
require('autoprefixer-core'),
require('postcss-color-rebeccapurple')
],
resolve: {
modulesDirectories: ['node_modules', 'components']
},
plugins: [
new ExtractTextPlugin('style.css', { allChunks: true })
]
如果,想更快的了解的话, 那就直接去线上 demo 看吧.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。