不管是用jquery还是react开发,都会遇到的一系列 CSS 的问题:
通过 JS 来管理 CSS 就很好解决上述列举的问题。CSS 模块化的解决方案有很多,但主要有两类。
一类是彻底抛弃 CSS,使用 JS 或 JSON 来写样式。Radium, jsxstyle ,react-style 属于这一类。优点是能给 CSS 提供 JS 同样强大的模块化能力;缺点是不能利用成熟的 CSS 预处理器(或后处理器) Sass/Less/PostCSS, :hover 和 :active 伪类处理起来复杂。
另一类是依旧使用 CSS,但使用 JS 来管理样式依赖,代表是CSS Modules。CSS Modules 能最大化地结合现有 CSS 生态和 JS 模块化能力。发布时依旧编译出单独的 JS 和 CSS。它并不依赖于 React,只要你使用 Webpack,可以在 Vue/Angular/jQuery 中使用。
// webpack.config.js css?modules&localIdentName=[name]__[local]-[hash:base64:5]
加上 modules 即为启用, localIdentName 是设置生成样式的命名规则,[name]表示标签名,[local]表示类名,[hash:base64:5]是按照给定算法生成的序列码。
/* components/test.css */ .active { color: red; } .disabled { color: gray; } /* components/test.js */ import styles from './test.css'; console.log(styles); elem.outerHTML = `<h1 class=${styles.active}>CSS Modules</h1>`
生成的 HTML 是
<h1 class="h1--active-abc53"> Processing... </h1>
它将根据 styleName 的值在关联的 style 对象中查找对应的 CSS Modules,并为 ReactElement className 属性值添加相匹配的独一无二的 CSS 类名。
上例中 styles的consolelog 打印的结果是:
Object { active: 'h1--active-abc53', disabled: 'h1--disabled-def84', }
CSS Modules 对 CSS 中的 class 名都做了处理,使用对象来保存原 class 和定制处理后的 class 的对应关系。经过这样类名定制处理后,class 名基本就是唯一的,大大降低了项目中样式覆盖的几率。同时可以生成更短的 class 名,减少代码量。
:local
: 做 localIdentName
规则处理 :global
: 样式编译后不变
如果书写时不加,默认处理为 :local
。
.normal { color: green; } :local(.normal) { color: green; } /* 上面两个等价,默认给每个 class 名外加加了一个 `:local` */ /* 全局样式 */ :global { .link { color: green; } .box { color: yellow; } }
开启CSS Modules时定义的规则 localIdentName=[name]__[local]-[hash:base64:5]
会控制对class名的处理, [hash:base64:5]定义的hash计算能保证类名的唯一性。
很多时候我们都需要样式复用,在 CSS Modules 中,一个选择器可以继承另一个选择器的规则,这称为 composes
组合。
/* components/test.css */ .bg { background-color: blue; } .title { composes: bg; color: white; } /* components/test.js */ import styles from './test.css'; elem.outerHTML = `<h1 class=${styles.title}>CSS Modules</h1>`
生成的 HTML 为
<h1 class="h1--bg-fec53 h1--title-Ijf8"> Processing... </h1>
:export 关键字可以把 CSS 中的 变量输出到 JS 中:
/* index.scss */ $primary-color: #f40; :export { primaryColor: $primary-color; } /* app.js */ import style from 'index.scss'; // 会输出 #F40 console.log(style.primaryColor);
module: { loaders: [{ test: //.jsx?$/, loader: 'babel' }, { test: //.scss$/, exclude: path.resolve(__dirname, 'src/styles'), loader: 'style!css?modules&localIdentName=[name]__[local]!sass?sourceMap=true' }, { test: //.scss$/, include: path.resolve(__dirname, 'src/styles'), loader: 'style!css!sass?sourceMap=true' }] }