CSS Module用法總結


 

什么是CSS Modules?

官方解釋是:GitHub - css-modules/css-modules: Documentation about css-modules

可以理解為:所有的類名和動畫名稱默認都有各自的作用域的css文件。

通俗點來說是,每個class類是獨立的可以被單獨的按照某種規則編譯為獨一無二的域名,或者你也可以理解為,每個class都有自己的scope。

css作用域

目前css作用域有三種方案

1.css modules

2.css in js

3.BEM +scope

其中1、3的區別如下

  1. 只要是靠人去保證代碼質量總是不靠譜的,人的狀態有起伏,但是機器沒有,因此推薦用機器去解決這些問題。這個是BEM+scope比較欠缺的
  2. 需要注意css穿透,如果要改一些第三方的東西(當然寫起來也比較簡單),具體的可以了解下樣式穿透
  3. BEM寫起來很繁瑣,而且是靠人去解決重名的問題。

那么cssModule解決了什么問題?

1.變量全局污染問題

css scope也能解決這個問題,但是解決問題的思路不一樣,scope解決全局樣式污染的問題的解決辦法是通過,scope來限制子作用域對父作用域(也可以是全局作用域)的污染

css module解決辦法是通過

:local(.text){
  color:red
}

:local函數來解決這個問題

:global(.class){
}

:global能在子頁面內寫全局變量(我們在修改第三方庫的時候通常會使用這個函數)

2.對比BEM,BEM相對繁瑣,而CSS Modulex相對靈活 

勝出原因:

  1.BEM的解決辦法是通過人來保證css的唯一性,CSS Module是通過webpack的打包機制類解決這個問題。

  打包代碼之前

<h1 class="test">
  An example heading
</h1>

  打包代碼之后

<h1 class="_styles__test_309571057">
  An example heading
</h1>

  2.靈活,並且不同css文件內即使相同的class也不會互相影響

  舉個栗子

import real from  './real.css'
import fake from './fake.css'
element.innerHTML = `<div class="${buttons.red} ${padding.large}">`;

  本質上,這種引入兩個文件夾的寫法是完全可以的,但是有些時候這種形式的代碼復用是很實用的,還有一個不經常用的寫法

.element {
composes: dark-red from "./colors.css";
font-size: 30px;
line-height: 1.2;
}

  借助CSS Module的compose,來解決這個事情。 

那么怎么使用CSS Module?

看了阮一峰大大的CSS Module教程,總結如下:

使項目支持CSS Module

安裝對應的包

因為在這里我們用的是 TypeScript,所以可以用 typings-for-css-modules-loader這個包,這個包也可以替代 css-loader的功能,此外這個包還能根據 .scss文件里面的類名自動生成對應的 .d.ts文件:
 
npm install -D typings-for-css-modules-loader

配置webpack
這個配置接非常簡單了,因為要用typings-for-css-modules-loader替代css-loader的功能,所以直接替換即可,將前面sass的配置修改為如下:

 

 

配置后在頁面中引入,引入可能會提示找不到該模塊,出現這個問題的原因是:

因為.scss文件中並沒有類似export這樣的關鍵詞用於導出一個模塊,所以也就導致報錯找不到模塊,這個問題需要通過ts的模塊聲明解決。(declare module)

解決聲明模塊問題

在根目錄新建一個typings文件夾,存放.scss的模塊聲明,以及后續需要用到的全局interface等,結構和聲明內容如下:

 

 接下來就可以愉快的寫CSS module了

CSS Module 全局作用域

CSS Modules 允許使用:global(.className)的語法,聲明一個全局規則。凡是這樣聲明的class,都不會被編譯成哈希字符串。

.title {
  color: red;
}

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

App.js使用普通的class的寫法,就會引用全局class

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

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

CSS Modules 還提供一種顯式的局部作用域語法:local(.className),等同於.className,所以上面的App.css也可以寫成下面這樣。 

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

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

定制哈希類名

css-loader默認的哈希算法是[hash:base64],這會將.title編譯成._3zyde4l1yATCOkgn-DBWEL這樣的字符串。

webpack.config.js里面可以定制哈希字符串的格式。(此處引用typings-for-css-modules-loader沒有嘗試過定制哈希,你們可以用css-loader的方式嘗試一下)

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

然后.tille 就變成了 (路徑名)_title__2DtM1

Class組合

在CSS Modules中,一個選擇器可以繼承另一個選擇器的規則,這稱為組合(composition)

.className {
  background-color: blue;
}

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

輸入變量

CSS Modules 支持使用變量,不過需要安裝 PostCSS 和 postcss-modules-values

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

postcss-loader加入webpack.config.js

const 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;
}

參考:https://zhuanlan.zhihu.com/p/99748333

參考:http://www.ruanyifeng.com/blog/2016/06/css_modules.html

點贊👍+關注我吧~

我只想成為更好的自己


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM