2

 CSS模块化遇到了哪些问题?

* 全局污染
* 命名混乱
* 依赖引入复杂
* 无法共享变量
* 代码冗余

 CSS Modules模块化方案

CSS Modules能最大化地结合现有CSS生态和JavsScript模块化能力,其API非常简洁,学习成本几乎为零。

CSS Modules实现以下几点

* 所有样式都是局部化,解决了命名冲突和全局污染的问题
* class名的生成规则配置灵活,可以以此来压缩 class 名
* 只需引用组件的 JavsScript,就能搞定组件所有的 JavsScript 和 CSS

具体先看以下实例:

importReactfrom'react';
importstylefrom'./App.module.css'; 

exportdefault () => {
  return (
    <h1className={style.title}>
      Hello World
    </h1>
  );
};

App.css

.title {
  color: red;
}

构建结果会将类名style.title编译成一个哈希字符串。

<h1class="_3zyde4l1yATCOkgn-DBWEL">
  Hello World
</h1>
._3zyde4l1yATCOkgn-DBWEL {
  color: red;
}

 CSS Modules使用特点

+ 不使用选择器,只使用 class 名来定义样式
+ 不层叠多个 class,只使用一个 class 把所有样式定义好
+ 不嵌套class
+ 所有样式通过 composes 组合来实现复用

 CSS Modules 语法

 作用域

CSS的规则都是全局的,任何一个组件的样式规则,都对整个页面有效。

产生局部作用域的唯一方法,就是使用一个独一无二的class的名字,不会与其他选择器重名。这就是 CSS Modules 的做法。

CSS Modules 默认样式为局部作用域,还提供一种显式的局部作用域语法:local(.className),等同于.className。  

如果需要定义一个全局作用域样式时,允许使用:global(.className)的语法,声明一个全局规则。凡是这样声明的class,都不会被编译成哈希字符串。

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

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

 Class 的组合

compose组合class样式复用,在 CSS Modules 中,一个选择器可以继承另一个选择器的规则, 自身引入的声明的优先级会比较高。

 注意:只有局部作用域规则才可以使用composes进行组合
/* 同一个css文件中复用类*/
.bg {
  background-color:blue;
}
  
.title {
  composes:bg;
  color:white;
}

/* 不同css文件中复用类*/
.title {
  composes: blue from './color.css';
  border-bottom: 1pxsolid #ccc;
  padding-bottom: 20px;
} 

/* 全局样式利用*/
.title {
  composes: text-blue from global;
  border-bottom: 1pxsolid #ccc;
  padding-bottom: 20px;
}

这个与预处理器的 @extends 语法很相似,我们用Sass来做实例比较:

.Button-common { /\* font-sizes, padding, border-radius \*/ }
.Button-normal {
  @extends .Button--common;
  color: blue;
}
.Button-error {
  @extends .Button--common;
  color: red;
}

编译成css后:

.Button-common, .Button-normal, .Button-error {
/* font-sizes, padding, border-radius */
}
.Button-normal {
  color:blue;
}
.Button-error {
  color:red;
}

然后,我们在HTML标签中使用一个样式名 <button class=“button--error”>, 即可获得所需的通用和特定样式。

再来看看CSS Modules的处理方式

.common { /* font-sizes, padding, border-radius */ }
.normal {
  composes: common;
  color:blue;
}
.error {
  composes: common;
  color:red;
}

在浏览器上,最终会编译成这样(样式名称规则通过构建工具加载器配置):

.submit_button__common__abc5436 { /* font-sizes, padding, border-radius */ }
.submit_button_normal__def6547 {
  color:blue;
}
.submit_button__error__1638bcd {
  color:red;
}

在js中使用 import styles from "./submit-button.css" 返回的对象可以看到最终是记录了多个样式名。


styles: {
  common: "submit_button_common__abc5436",
  normal: "submit_button_common_abc5436 submit_button_normal__def6547",
  error: "submit_button_common_abc5436 submit_button_error__1638bcd"
}

这是composes的强大功能,您可以组合多个独立的样式组,而无需更改标记或重写CSS选择器。

 嵌套

CSS Modules 允许嵌套定义,但并不推荐这样做。

.title-bar {
  height: 48px
}

.title-bar>ul {
  text-align: center
}

.titel-bar:global(.cell) {
  padding-left:10px
}

 和预处理器配合使用

通过构建工具的配置,可以和各种CSS预处理器一起使用,如stylus

@import"~@/assets/css/vendor"

.logo
  width: 200px
  text-align: center
  &:hover
    background: $bg /* vendor中定义的变量 */

.round {
  display: inline-block
  width: 30px
  height: @width
  line-height: @width
  border-radius: 50%
  composes: bg-main from global;
}

 参考链接

Create React App

Vue-loader

react-css-modules

CSS Modules: Welcome to the Future

CSS Modules用法教程


有饭
97 声望1 粉丝