為什么需要CSS模塊化 ?
由于CSS的規(guī)則是全局性的,添加任何一個(gè)樣式,在全局都有效,優(yōu)點(diǎn)是方便復(fù)用,缺點(diǎn)是會(huì)根據(jù)權(quán)重的計(jì)算造成樣式?jīng)_突,非常難以管理。
CSS 模塊化的方案
有了釘子,自然就會(huì)有錘子。隨著前端的發(fā)展出現(xiàn)了各種CSS模塊解決方案,主要分兩種:
一類是采用JS或者JSON 的方式寫CSS,比如 jsxstyle,react-style,雖然可以采用JS成熟方案來管理css, 但是它無法使用postcss ,sass等css預(yù)處理器,并且衍生了大批的api, 使用的代價(jià)較大。
另一類還是采用css 來寫樣式, 不過是通過工具生成CSS作用域的方式實(shí)現(xiàn)模塊化,比如CSS module。常用的BEM命名技巧或者團(tuán)隊(duì)中約定的方案來實(shí)現(xiàn)命名空間從而實(shí)現(xiàn)模塊化,不過約定總會(huì)出現(xiàn)問題,于是就出現(xiàn)了通過工具,比如webpack的css-loader根據(jù)算法,實(shí)現(xiàn)css 模塊化。
啟用CSS
webpack 內(nèi)置的 css-loader 自帶了CSS modoule, 配置如下:
rules: [
...
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[name]__[local]--[hash:base64:5]' // 生成樣式的命名規(guī)則
}
//或者采用loader: 'css?modules&localIdentName=[name]__[local]-[hash:base64:5]'的寫法
}
]
}
]
create-react-app 2.0以上的版本中內(nèi)置啟動(dòng)了CSS module, 如果需要特殊配置,則需要eject操作, 在webpack.config.js 中:
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
// using the extension .module.css
{
test: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction && shouldUseSourceMap,
modules: true,
getLocalIdent: getCSSModuleLocalIdent,
}),
},
CSS module 用法
基本用法
/* components/Button.css */
.normal { /* normal 相關(guān)的所有樣式 */ }
.disabled { /* disabled 相關(guān)的所有樣式 */ }
// components/Button.js
import styles from './Button.css';
buttonElem.outerHTML = `<button class=${styles.normal}>Submit</button>`
//生成的HTML
<button class="button--normal-abc53">Submit</button>
CSS module 默認(rèn)采用局部樣式,即給每個(gè)css 名添加上了“:local”, 對(duì)應(yīng)的全局性的寫法:
/* 定義全局樣式 */
:global(.btn) {
color: red;
}
/* 定義多個(gè)全局樣式 */
:global {
.link {
color: green;
}
.box {
color: yellow;
}
}
compose 組合樣式:
對(duì)于樣式復(fù)用,CSS module提供了唯一的方式 "compose":
/* components/Button.css */
.base { /* 所有通用的樣式 */ }
.normal {
composes: base;
/* normal 其它樣式 */
}
.disabled {
composes: base;
/* disabled 其它樣式 */
}
import styles from './Button.css';
buttonElem.outerHTML = `<button class=${styles.normal}>Submit</button>`
// 生成后的html
<button class="button--base-fec26 button--normal-abc53">Submit</button>
多CSS class 的寫法:
.normal {
composes: base;
/* normal 其它樣式 */
}
.disabled {
composes: base;
/* disabled 其它樣式 */
}
import styles from './Button.css';
buttonElem.outerHTML = `<button className={ `${styles.normal} ${style.disbale} `}>Submit</button>`
Sass 變量與JS共享
/* config.scss */
$primary-color: #f40;
// 內(nèi)置語法,可以到處該變量
:export {
primaryColor: $primary-color;
}
/* app.js */
import style from 'config.scss';
// 會(huì)輸出 #F40
console.log(style.primaryColor);
使用技巧
Css module 作者建議:
1.不使用選擇器,只使用 class 名來定義樣式
2.不層疊多個(gè) class,只使用一個(gè) class 把所有樣式定義好
3.不嵌套
4.使用 composes 組合來實(shí)現(xiàn)復(fù)用
Css module 在React中的實(shí)踐
采用classnames來增強(qiáng)CSS module 在react 中的使用,類似Angular 中的樣式指令:
var classNames = require('classnames');
class Button extends React.Component {
// ...
render () {
var btnClass = classNames({
btn: true,
'btn-pressed': this.state.isPressed,
'btn-over': !this.state.isPressed && this.state.isHovered
});
return <button className={btnClass}>{this.props.label}</button>;
}
}
應(yīng)用全局樣式
...
// 引入全局樣式
import 'xxx/common.css';
// 引入局部樣式
import styles from './xxx.module.css';
...
<div className={styles.wrapper}>
<!-- 同時(shí)引入全局、局部樣式,且如果className帶中劃線,用['className']代替 -->
<button className={`btn ${styles['my-btn']}`}>save</button>
</div>
...