CSS Modules 实例代码


作者: 阮一峰

Demo01: Local Scope

demo / sources

CSS rules are global. The only way of making a local-scoped rule is to generate a unique class name, so no other selectors will have collisions with it. That is exactly what CSS Modules do.

The following is a React component App.js.

import React from 'react';
import style from './App.css';

export default () => {
  return (
    <h1 className={style.title}>
      Hello World
    </h1>
  );
}; 

In above codes, we import a CSS module from App.css into a style object, and use style.title to represent a class name.

.title {
  color: red;
} 

The build runner will compile the class name style.title into a hash string.

<h1 class="_3zyde4l1yATCOkgn-DBWEL">
  Hello World
</h1> 

And App.css is also compiled.

._3zyde4l1yATCOkgn-DBWEL {
  color: red;
} 

Now this class name becomes unique and only effective to the App component.

CSS Modules provides plugins for different build runners. This repo uses css-loader for Webpack, since it support CSS Modules best and is easy to use. By the way, if you don't know Webpack, please read my tutorial Webpack-Demos.

The following is our webpack.config.js.

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"
      },
    ]
  }
}; 

The magic line is loader: "style-loader!css-loader?modules", which appends the query parameter modules after css-loader enabling the CSS Modules feature.

Now run the demo.

$ npm run demo01 

Open http://localhost:8080, you should see the h1 in red.

Demo02: Global Scope

demo / sources

The syntax :global(.className) could be used to declare a global selector explicitly. CSS Modules will not compile this class name into hash string.

First, add a global class into App.css.

.title {
  color: red;
}

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

Then use the global CSS class in App.js.

import React from 'react';
import styles from './App.css';

export default () => {
  return (
    <h1 className="title">
      Hello World
    </h1>
  );
}; 

Run the demo.

$ npm run demo02 

Open http://localhost:8080, you should see the h1 title in green.

CSS Modules also has a explicit local scope syntax :local(.className) which is equivalent to .className. So the above App.css could be written in another form.

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

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

Demo03: Customized Hash Class Name

demo / sources

CSS-loader's default hash algorithm is [hash:base64], which compiles.title into something like ._3zyde4l1yATCOkgn-DBWEL.

You could customize it in webpack.config.js.

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

Run the demo.

$ npm run demo03 

You will find .title hashed into demo03-components-App---title---GpMto.

Demo04: Composing CSS Classes

demo / sources

In CSS Modules, a selector could inherit another selector's rules, which is called "composition".

We let .title inherit .className in App.css.

.className {
  background-color: blue;
}

.title {
  composes: className;
  color: red;
} 

App.js is the same.

import React from 'react';
import style from './App.css';

export default () => {
  return (
    <h1 className={style.title}>
      Hello World
    </h1>
  );
}; 

Run the demo.

$ npm run demo04 

You should see a red h1 title in a blue background.

After the building process, App.css is converted into the following codes.

._2DHwuiHWMnKTOYG45T0x34 {
  color: red;
}

._10B-buq6_BEOTOl9urIjf8 {
  background-color: blue;
} 

And the HTML element h1's class names should look like <h1 class="_2DHwuiHWMnKTOYG45T0x34 _10B-buq6_BEOTOl9urIjf8">,

Demo05: Import Other Modules

demo / sources

You also could inherit rules from another CSS file.

another.css

.className {
  background-color: blue;
} 

App.css

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

Run the demo.

$ npm run demo05 

You should see a red h1 title in a blue background.

Demo06: Exporting Values Variables

demo / sources

You could use variables in CSS Modules. This feature is provided by PostCSS and the postcss-modules-values plugin.

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

Add postcss-loader into 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
  ]
}; 

Next, set up your values/variables in colors.css.

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

Then import them into App.css.

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

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

Run the demo.

$ npm run demo06 

下载地址