CSSModules

子木_lsy發表於2019-02-24

這篇文章來一起了解 css 模組化的用法和原理 ,dome 地址:css modules ?


區域性作用域

一般我們引入頁面的CSS的作用域都是全域性的,都是對這個頁面起作用,產生區域性的作用域,就是使用一個獨一無二的class的名稱,不會和其它選擇器重名的,CSS Modules 就是這個原理。下面我們看一段程式碼

import $ from `jquery`;
import styles from `./main.css`;
import test from `./test.html`;

$(`body`).append($(`<div><h1>我會變綠</h1></div>`));
$(`div h1`).addClass(styles.testGreen);
$(`body`).append(test).find(`h2`).addClass(styles.testBlue);
複製程式碼

上面的程式碼我把main.css輸入到style物件,然後下面用了styles.testGreen物件的屬性形式呼叫,就會應用main.css裡的樣式

.testGreen {
  color: green;
}
複製程式碼

構建工具(webpack)編譯成一個雜湊字串

<div>
    <h1 class="_305zeUSoiGREv3GqPa9H8F">我會變綠</h1>
</div>
複製程式碼

main.css也會同時編譯

._305zeUSoiGREv3GqPa9H8F {
  color: #aaf200;
}
複製程式碼

這樣一來,這個類名就是獨一無二的了,只對應用的元件有效。
**CSS Modules**支援不同的構建工具,這裡我使用的是webpack,下文都是以webpack為例。
下面我們來看下 webpack.config.js

module.exports = {
  context: __dirname + `/src`,
  devtool: `eval-source-map`, //配置生成Source Maps,選擇合適的選項
  entry: {
    app: [`./app.js`, `./test.js`],
  },
  output: {
    path: __dirname + `/dist`,
    filename: `bundle.js`,
    publicPath: `/assets`,
  },
  module: {
    loaders: [
      {test: /.json$/,loader: `json-loader`},
      {test: /.js$/,exclude: /node_modules/,loader: `babel-loader`},
      {test: /.css$/,loader: ExtractTextPlugin.extract({
          fallbackLoader: "style-loader",
          loader: {
            loader: "css-loader",
            query: {
              modules: true
            }
          }
        })
      },
      {test: /.html$/,loader: `html-loader`},
    ]
  },
  plugins: [
    new ExtractTextPlugin(`style.css`)
  ]
};
複製程式碼

上面的程式碼可以看到,query:{modules:true}代表開啟 CSS Modules 模組,這裡還配置了把所以得css合併一個檔案,具體的可以瞭解webpackextract-text-webpack-plugin外掛。

全域性作用域

CSS Modules 允許用:global(.className)的語法宣告一個全域性的作用域。加了:global的不會被編譯成雜湊值。

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

.title {
  color: red;
}
複製程式碼

test.js使用普通的寫法,就會引用全域性的.title的樣式

import $ from `jquery`;
import styles from `./main.css`;
import test from `./test.html`;

$(`body`).append($(`<div><h1>我是title</h1></div>`));
$(`div h1`).addClass(`title`);
複製程式碼

結果h1的title顯示黑色。

Class的組合

CSS Modules 裡,一個選擇器可以繼承另一個選擇器。

mian.css裡,我讓.testBlue繼承.testBg

.testBg {
  background-color: red;
}

.testBlue {
  color: blue;
  composes: testBg;
}
複製程式碼

不用修改test.js,應用了.testBlue就會有一個紅色的背景。
編譯結果:

.eh33VC37uFHXkCZ8LfKYd {
  background-color: #ff0000;
}

.xrmZso54fTBX29J9G65Ai {
  color: #0c77f8;
}
複製程式碼

相應的html程式碼:

<h3 class="xrmZso54fTBX29J9G65Ai eh33VC37uFHXkCZ8LfKYd _2gsuNWm9029FHPYJP62C-t">
    我會變藍
</h3>
複製程式碼

輸入變數

CSS Modules 支援使用變數,不過要安裝 PostCSSpostcss-modules-values

$ npm install --save postcss-loader postcss-modules-values
複製程式碼

postcss-loader加入webpack.config.js.

{
    test: /.css$/,
    loader: `style-loader!css-loader?modules!postcss-loader`
},
複製程式碼

然後我在colors.css裡定義了一些變數。

@value blue: #0c77f8;
@value red: #ff0000;
@value green: #aaf200;
複製程式碼

main.css裡可以這樣引用變數

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

.title {
  color: red;
}

.testBg {
  background-color: red;
}

.testGreen {
  color: green;
}

.testBlue {
  color: blue;
  composes: testBg;
  composes: div;
}
複製程式碼

這樣就可以把colors.css的變數拿過來用了,是不是很神奇。