Trouble
全局污染
.container {
.title {
& > span {
}
}
.content {
p {
}
.side {
}
}
}
命名混乱
/*小A*/
.container {}
.container-header {}
.container-footer {}
/*小B*/
.container2 {}
.container2-header {}
.container2-footer {}
less
<section class="abc-container">
<h1 class="title">this is title</h1>
<div class="content">
<p>this is <span class="bar">content</span></p>
</div>
</section>
.abc-container {
.title {
color: red;
font-size: 14px;
}
.content {
margin: 20px;
.bar {
color: blue;
font-size: 20px;
}
}
}
[note] 这是我们现在的less写法,我们使用命名空间来确保样式不会冲突。随着这个页面越来越复杂,就变成了这样: [/note]
[note] 这样,一个 less 就会上百行,后期也并不好维护。其实,我们这么写只是为了解决样式冲突问题而已,而这一点 CSS Modules 早就完美解决了。 [/note]
CSS Modules
import styles from './style.css'
class Demo extends React.Component {
render() {
return (
<section>
<h1 className={styles.title}>this is title</h1>
<div className={styles.content}>
<p>this is <span className={styles.bar}>content</span></p>
</div>
</section>
)
}
}
/* style.css */
.title {
color: red;
font-size: 14px;
}
.content {
margin: 20px;
}
.bar {
color: blue;
font-size: 20px;
}
[note] 解决了什么问题? 不必再有类似 abc-container
的命名空间了,这个页面和别的页面样式绝不会冲突,哪怕class名字是一样的! [/note]
theory
[note] 为什么绝对不会冲突?现在来介绍一下 CSS Modules 的原理 [/note]
webpack config
webpack 的 css-loader 的 localIdentName
配置项::
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader?modules&localIdentName=[name]__[local]-[hash:base64:5]'
]
}
]
}
[note] modules:: 开启 CSS Modules localIdentName:: 具体生成规则,name、local在加hash保证绝对不会冲突 [/note]
Use
[note] CSS Module 很简单,几乎是零成本。 [/note]
作用域
.title {
color: red;
}
:global(.title) {
color: green;
}
:global {
.title {}
}
[note] 凡是这样声明的 .title
,都不会被编译成哈希字符串。 [/note]
样式复用
.className {
color: green;
background: red;
}
.otherClassName {
composes: className;
color: yellow;
}
||
.otherClassName {
background: red;
color: yellow;
}
引入其他文件样式
.otherClassName {
composes: className from "./style.css";
}
简化 composes 路径
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[local]___[hash:base64:5]',
importLoaders: 1,
alias: {
containers: ROOT + '/src/containers',
}
}
}
.otherClassName {
composes: className from '../../../style.css';
}
.otherClassName {
composes: className from 'containers/A/style.css';
}
以上是 CSS Modules 的所有功能,具体可看官方demo
变量(结合 postcss)
- postcss-loader
- postcss-modules-values
- 根目录新建 postcss.config.js
module.exports = {
plugins: [
require('postcss-modules-values')
]
}
- webpack.config.js
{
test: /\.css$/,
use: [
'style-loader',
'css-loader?modules&localIdentName=[name]__[local]-[hash:base64:5]&importLoaders=1',
'postcss-loader'
]
}
importLoaders 必须设置,具体见 css-loader 的文档
[note] 因为 CSS Modules 设计得及其简单,所以一些功能可以用 postcss 实现 [/note]
[note] postcss 等同于 JS 中的 babel,是用标准的CSS语法转译为 CSS less/sass 等同与 JS 中的 coffee,是用自己的语法转译为 CSS [/note]
变量共享 (结合postcss)
@value xxx: #c1c3c4;
.title {
color: xxx;
}
.content {
color: xxx;
}
// CSS、JS变量共享,这是 CSS Modules 独有的功能
import styles from './style.css';
console.log(styles.xxx) ; //#c1c3c4
在 React 使用 CSS Modules
import styles from './style.css'
class Demo extends React.Component {
render() {
return (
<section>
<h1 className={styles.title}>this is title</h1>
<div className={styles.content}>
<p>this is <span className={styles.bar}>content</span></p>
</div>
</section>
)
}
}
为了避免太多的 style.
,使用 babel 插件 react-css-modules::
// .babelrc
{
"plugins": [
["react-css-modules",
{
"generateScopedName":"[local]___[hash:base64:5]"
}
]
]
}
import './style.css'
class Demo extends React.Component {
render() {
return (
<section>
<h1 styleName="title">this is title</h1>
<div styleName="content">
<p>this is <span styleName="bar">content</span></p>
</div>
</section>
)
}
}