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

点赞👍+关注我吧~

我只想成为更好的自己

posted @ 2020-12-17 16:55  文学少女  阅读(2442)  评论(0编辑  收藏  举报