CSS Modules - CSS模块化

参考文章:
CSS Modules 用法教程-阮一峰
css module
css模块化及CSS Modules使用详解

背景-CSS 模块化

CSS 模块化的解决方案有很多,但主要有两类:
一类是彻底抛弃 CSS,使用 JS 或 JSON 来写样式。Radium,jsxstyle,react-style 属于这一类。

  • 优点是能给 CSS 提供 JS 同样强大的模块化能力;
  • 缺点是不能利用成熟的 CSS 预处理器(或后处理器) Sass/Less/PostCSS,:hover 和 :active 伪类处理起来复杂。

另一类是依旧使用 CSS但使用 JS 来管理样式依赖,代表是 CSS Modules。

  • CSS Modules 能最大化地结合现有 CSS 生态和 JS 模块化能力,API 简洁到几乎零学习成本。
  • 发布时依旧编译出单独的 JS和 CSS。
  • 它并不依赖于 React,只要你使用 Webpack,可以在 Vue/Angular/jQuery 中使用。
  • 是我认为目前最好的CSS 模块化解决方案

前言

CSS Modules 提供各种插件,支持不同的构建工具。
本文使用的是 Webpackcss-loader插件,因为它对 CSS Modules 的支持最好,而且很容易使用。

为什么需要CSS Modules

解决类名冲突问题
CSS的规则都是全局的,任何一个组件的样式规则,都对整个页面有效。因此,为了使用独特的样式,要保证元素的类名不冲突。这对于大型项目而言是很难的。
CSS Modules的思路:
产生一个独一无二的class的名字,不会与其他选择器重名

实现原理

  1. 开启了css module后,构建工具webpack的css-loader会将样式中的类名进行转换,转换为一个唯一的hash值
    CSS Modules - CSS模块化_第1张图片
    由于hash值是根据模块路径和类名生成的,因此,不同的css模块,哪怕具有相同的类名,转换后的hash值也不一样。

  2. 根据导出结果可知,我们就可以在js代码中获取到css模块导出的结果,从而应用类名

// src/index.js
import style from  "./assets/style.css"
console.log(style)
const div = document.getElementById("div1");
div.className = style.c1;

打印结果如下:
在这里插入图片描述

语法

参考CSS Modules 用法教程-阮一峰

0.配置

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

关键的一行是style-loader!css-loader?modules,它在css-loader后面加了一个查询参数modules,表示打开 CSS Modules 功能。

0.1初始代码

App.css:

.title {
  color: red;
}

React组件App.js:

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

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

1. 局部作用域

使用了 CSS Modules 后,样式默认局部
相当于给每个 class 名外加加了一个 :local,以此来实现样式的局部化

.normal {
  color: green;
}

/* 以上与下面等价 */
:local(.normal) {
  color: green; 
}

同上。h1标题会显示为红色

2.全局作用域

CSS Modules 允许使用**:global(.className)**的语法,声明一个全局规则。
凡是这样声明的class,都不会被编译成哈希字符串。
e.g.
App.css加入一个全局class:

.title {
  color: red;
}
:global(.title) {
  color: green;
}
/* 定义多个全局样式 */
:global {
  .link {
    color: green;
  }
  .box {
    color: yellow;
  }
}

App.js使用普通的class的写法:

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

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

h1标题显示为绿色。

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

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

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

3.定制哈希类名

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

webpack.config.js里面可以定制哈希字符串的格式:

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

你会发现.title被编译成了demo03-components-App---title---GpMto

4.Class的组合

在 CSS Modules 中,一个选择器可以继承另一个选择器的规则,这称为"组合"(“composition”)
在App.css中,让.title继承.className

.className {
  background-color: blue;
}

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

运行,会看到红色的h1在蓝色的背景上。

打印App.js中导入的style,结果如下:
在这里插入图片描述

5.输入其他模块

选择器也可以继承其他CSS文件里面的规则
e.g. another.css文件

.className {
  background-color: blue;
}

App.css继承another.css里面的规则

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

蓝色的背景上有一个红色的h1(相当于class的组合,只不过来自另一个文件)

6.输入变量

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

  1. 把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
  ]
};
  1. 在colors.css里面定义变量
@value blue: #0c77f8;
@value red: #ff0000;
@value green: #aaf200;
  1. App.css可以引用这些变量
@value colors: "./colors.css";
@value blue, red, green from colors;

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

会看到蓝色的背景上有一个红色的h1

项目使用

一般的脚手架都默认集成了 CSS Modules,比如 React 官方的脚手架create-react-app,已经将 CSS Modules 集成进来了,可以直接使用。
我有个问题,蚂蚁的前端脚手架Ant Design Pro是基于react的,这是不是意味着它默认也集成了 CSS Modules。(当然,它的确是集成了的,只是,是不是基于react的脚手架也都默认集成了CSS Modules)

你可能感兴趣的:(#,CSS,css,webpack,javascript)