为什么需要CSS模块化 ?
由于CSS的规则是全局性的,添加任何一个样式,在全局都有效,优点是方便复用,缺点是会根据权重的计算造成样式冲突,非常难以管理。
CSS 模块化的方案
有了钉子,自然就会有锤子。随着前端的发展出现了各种CSS模块解决方案,主要分两种:
一类是采用JS或者JSON 的方式写CSS,比如 jsxstyle,react-style,虽然可以采用JS成熟方案来管理css, 但是它无法使用postcss ,sass等css预处理器,并且衍生了大批的api, 使用的代价较大。
另一类还是采用css 来写样式, 不过是通过工具生成CSS作用域的方式实现模块化,比如CSS module。常用的BEM命名技巧或者团队中约定的方案来实现命名空间从而实现模块化,不过约定总会出现问题,于是就出现了通过工具,比如webpack的css-loader根据算法,实现css 模块化。
启用CSS
webpack 内置的 css-loader 自带了CSS modoule, 配置如下:
rules: [
...
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[name]__[local]--[hash:base64:5]' // 生成样式的命名规则
}
//或者采用loader: 'css?modules&localIdentName=[name]__[local]-[hash:base64:5]'的写法
}
]
}
]
create-react-app 2.0以上的版本中内置启动了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 相关的所有样式 */ }
.disabled { /* disabled 相关的所有样式 */ }
// 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 默认采用局部样式,即给每个css 名添加上了“:local”, 对应的全局性的写法:
/* 定义全局样式 */
:global(.btn) {
color: red;
}
/* 定义多个全局样式 */
:global {
.link {
color: green;
}
.box {
color: yellow;
}
}
compose 组合样式:
对于样式复用,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;
// 内置语法,可以到处该变量
:export {
primaryColor: $primary-color;
}
/* app.js */
import style from 'config.scss';
// 会输出 #F40
console.log(style.primaryColor);
使用技巧
Css module 作者建议:
1.不使用选择器,只使用 class 名来定义样式
2.不层叠多个 class,只使用一个 class 把所有样式定义好
3.不嵌套
4.使用 composes
组合来实现复用
Css module 在React中的实践
采用classnames来增强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>;
}
}
应用全局样式
...
// 引入全局样式
import 'xxx/common.css';
// 引入局部样式
import styles from './xxx.module.css';
...
<div className={styles.wrapper}>
<!-- 同时引入全局、局部样式,且如果className带中划线,用['className']代替 -->
<button className={`btn ${styles['my-btn']}`}>save</button>
</div>
...
网友评论