webpack CSS Module

  21 Jul 2017


CSS Module 局部作用域

CSS Modules 加入了局部作用域和模块依赖。

CSS规则都是全局的,任何一个组件的样式规则对整个页面都有效。

产生局部作用域唯一的办法就是使用一个独一无二的class名字,不会与其他的选择器重名。这就是CSS Modules 的做法。

例如:

var React =require('react');
var ReactDOM =require('react-dom');
var style =require('./app.css');
ReactDOM.render(
    <div>
      <h1 className={style.title}>Hello World</h1>
    </div>,
    document.getElementById('example')
)

上面代码中,我们将 app.css 输入到style对象,然后引用style.title表示一个class。

.title{
   color:red;
}

构建工具会将类名 style.title 编译成 一个哈希字符串。

<h1 class="l9td2F4yuAHHvsv8gzFp_ ">
  Hello World
</h1>

app.css 也同时会被编译

.l9td2F4yuAHHvsv8gzFp_  {
  color: red;
}

这样可以保证这个类名独一无二,只对这个组件有效果。

CSS Module提供各种插件,支持不同的构建工具,建议使用webpack css-loader插件。

webpack相关教程可见>webpack 整理

下面是示例的 webpack.config.js

module.exports={
 entry:'./main.js',
 output:{
 filename:'./bundle.js'
 },

  module: {
    loaders:[
      { test: /\.js[x]?$/, exclude: /node_modules/, loader: 'babel-loader?presets[]=es2015&presets[]=react' },
      { test: /\.css$/, loader: 'style-loader!css-loader?modules' }
    ]
  }

}

上面代码中,关键的是 style-loader!css-loader?modules,后面加了个查询参数 modules,它表示开启CSS Module 功能。


全局作用域

CSS Module 允许使用:global(.clasName)的语法,声明一个全局规则。凡是这样声明的calss都不会被编译成哈希字符串。

app.css 加入一个全局的 calss

.title{
   color:red;
}
:global(.litle){
 color: green;
}

main.js 使用普通的class写法,就会引用全局class

var React =require('react');
var ReactDOM =require('react-dom');
var style =require('./app.css');
ReactDOM.render(
    <div>
      <h1 className={style.title}>Hello World</h1>
      <h1 className='title'>Hello World</h1>
    </div>,
    document.getElementById('example')
)

CSS Modules 还提供一种显式的局部作用域语法:local(.className),等同于.className,所以上面的app.css也可以写成下面这样。

:local(.title) {
  color: red;
}

:global(.title) {
  color: green;
}

定制哈希类名

CSS-loader 默认的哈希算法是[ hash:base64 ],将会把.title编译成.l9td2F4yuAHHvsv8gzFp_这样的字符串。

webpack.config.js里面可以定制哈希字符串的格式。localIdentName表示命名规则

module:{
 loaders:[
 {
    test:/\.css$/,
    loader:"style-loader!css-loader?modules&localIdentName=[path][name]---[local]---[hash:base64:5]"
 }

 ]

}

运行这个示例,你会发现.title被编译成 .app—title—l9td2


Class的组合

在CSS Modules 中,一个选择器可以继承另一个选择器,这称为组合(composition)

在 app.css中,.title 继承 .className

.className{
  backgrund-color:bule;
}
.title{
 composes:className;
 color:red;
}

运行demo06 这个示例,会发现app.css 编译成了:

.app---className---1RcNP {
  background-color: blue;
}

.app---title---l9td2 {
  color:red;
}

.title {
  color: blue;
}

相应的 h1 的class 也被编译成 app—title—l9td2 app—className—1RcNP。

选择器也可以继承其他的CSS文件里的规则。

//another.css
.className {
  background-color: blue;
}

app.css可以继承another.css里面的规则。

.title {
  composes: className from './another.css';
  color: red;
}

Class的组合

CSS Modules 支持使用变量,不过需要安装 PostCSS 和 postcss-modules-values。

$ npm install –save postcss-loader postcss-modules-values

把postcss-loader加入webpack.config.js。

var values = require('postcss-modules-values');

module.exports = {
  entry: __dirname + '/index.js',
  output: {
    publicPath: '/',
    filename: './bundle.js'
  },
  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: 'babel',
        query: {
          presets: ['es2015', 'stage-0', 'react']
        }
      },
      {
        test: /\.css$/,
        loader: "style-loader!css-loader?modules!postcss-loader"
      },
    ]
  },
  postcss: [
    values
  ]
};

接着,在colors.css里面定义变量。

@value blue: #0c77f8;
@value red: #ff0000;
@value green: #aaf200;

app.css可以引用这些变量。

@value colors: "./colors.css";
@value blue, red, green from colors;

.title {
  color: red;
  background-color: blue;
}