css加载
style-loader
一般性配置:
js file:
import './message.css';
webpack:
module: {
loaders: [
{
test: /\.(scss|css)$/,
loaders: ['style', 'css', 'postcss']
}
]
},
postcss: function () {
return [require('autoprefixer'), require('precss'), require('postcss-calc')];
}
先引入postcss-loader处理,譬如precss将sass转成css,autoprefixer添加兼容性前缀。再由css-loader加载require的样式文件,最后style-loader将这些css转变成会插入到页面
最终
标签下会有非常多的}
}
最终样式会转成dom的inline style。
组件js代码里自行处理
还有一种不能算css 模块化的内容,但是是css in js的一种做法:
譬如material-ui,直接在组件内定义内容为css样式的变量,然后将其运用在组件的style标签上。
radium
radium相对于material-ui那种自行处理,做了一些封装,来提高开发效率
var Radium = require('radium');
var React = require('react');
var color = require('color');
@Radium
class Button extends React.Component {
static propTypes = {
kind: React.PropTypes.oneOf(['primary', 'warning']).isRequired
};
render() {
return (
style={[
styles.base,
styles[this.props.kind]
]}>
{this.props.children}
);
}
}
var styles = {
base: {
color: '#fff',
':hover': {
background: color('#0074d9').lighten(0.2).hexString()
}
},
primary: {
background: '#0074D9'
},
warning: {
background: '#FF4136'
}
};
优点:是能给 CSS 提供 JS 同样强大的模块化能力;
缺点是不能利用成熟的 CSS 预处理器(或后处理器) Sass/Less/PostCSS,:hover 和 :active 伪类处理起来复杂
css module
CSS Modules 内部通过 ICSS 来解决样式导入和导出这两个问题。分别对应 :import 和 :export 两个新增的伪类。
:import("path/to/dep.css") {
localAlias: keyFromDep;
/* ... */
}
:export {
exportedKey: exportedValue;
/* ... */
}
但直接使用这两个关键字编程太麻烦,实际项目中很少会直接使用它们,我们需要的是用 JS 来管理 CSS 的能力。结合 Webpack 的 css-loader 后,就可以在 CSS 中定义样式,在 JS 中导入
webpack配置:
// webpack.config.js
css?modules&localIdentName=[name]__[local]-[hash:base64:5]
给css-loader加上 modules参数 即为启用,localIdentName 是设置生成样式的命名规则。
定义css:
/* components/Button.css */
.normal { /* normal 相关的所有样式 */ }
.disabled { /* disabled 相关的所有样式 */ }
使用:
/* components/Button.js */
import styles from './Button.css';
console.log(styles);
buttonElem.outerHTML = `Submit`
生成的 HTML 是:
Submit
命名空间
css module里默认样式都是局部的,相当于给每个 class 名外加加了一个 :local,以此来实现样式的局部化。如果想切换到全局模式,需要指定 :global。
.normal {
color: green;
}
/* 以上与下面等价 */
:local(.normal) {
color: green;
}
/* 定义全局样式 */
:global {
.link {
color: green;
}
.box {
color: yellow;
}
}
样式复用
css module使用composes来复用样式:
.className {
color: green;
background: red;
}
.otherClassName {
composes: className;
color: yellow;
}
可以复用多个class的样式: composes: classNameA classNameB。
可以compose一个来源于其他文件的class:
.otherClassName {
composes: className from "./style.css";
}
composes 其实不是复用了具体的样式属性和值,而是会编译成多个class
import styles from './styles.css';
buttonElem.outerHTML = `Submit`
这段代码会转化成:
Submit
CSS,JS变量共享
使用:export 关键字可以把 CSS 中的 变量输出到 JS 中。
譬如在js中读取sass的变量:
/* config.scss */
$primary-color: #f40;
:export {
primaryColor: $primary-color;
}
/* app.js */
import style from 'config.scss';
// 会输出 #F40
console.log(style.primaryColor);
优势
样式默认都是局部的,解决了命名冲突和全局污染问题
只需引用组件的 JS 就能搞定组件所有的 JS 和 CSS
css代码依旧是css,学习成本低,符合长期形成的开发习惯
可以与预处理器共同使用
shadow dom
https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM
npm包组件里的css输出
把组件做成npm提供给其他人使用,参考现有的一些组件。主要有2种方式:
使用webpack将css合并成一个文件,js也合并成一个文件输出
仍按原组件结构,不拆分文件,对外提供入口文件供引入。这时候js和jsx文件会用babel编译一下。
我更喜欢2,这样源码能够被查看调试。但是途中遇到一些需要解决的问题:
sass、less文件的处理:用相应的编译器转成css。可以用webpack配置多入口(每个入口就一个css文件)的方式转成css,这其实不是在把webpack当合并打包工具使用了。。。我嫌麻烦,用了gulp。
用了gulp转成css后,原文件中的引用语句: import 'xxx.scss'会找不到。只能用gulp-replace在将文件里的’.scss’替换成’.css’。