利用CSS Module中的:global语法简化React样式隔离

308 阅读3分钟

说句废话:CSS Module方案的出现主要是为了解决React库中的缺少样式隔离方案的问题。本文是我在初次探索这种样式隔离方案时思考出的一种我自己觉得可行的写法,所以贴了出来和大家分享。该写法在第三部分:3. 利用:global简化样式隔离方案。 还有一些关于CSS Modules语法和特点的总结,在第1、2节。大家可以按需食用🍽️。

话不多说,进入干货!!

CSS Modules

参考教程:www.ruanyifeng.com/blog/2016/0…

1. CSS Modules特点:

  1. 使用css Modules时,导入样式文件会以对象形式导入,CSS Modules会将嵌套类名选择器的样式块名称提到对象的顶层。

    假如有如下结构:

    .wrapper{
      .b{
          .c{
            color:aqua;
          }
       }
    }
    

    导入的styles的对象的结构会是这样的:

    {
      b: "_b_1cf5l_11",
      c: "_c_1cf5l_1",
      wrapper: "_wrapper_1cf5l_11",
    }
    
  2. CSS Modules只会处理类选择器,并将其转换为全局唯一的类名;但不会对非类名选择器进行转换。

    .wrapper{
      h2{
        .b{
          .c{
            color:aqua;
          }
        }
      }
    }
    

    这种结构就转换后的styles的结构和上面结构相同。并不会将h2选择器进行转换

    {
      b: "_b_1cf5l_11",
      c: "_c_1cf5l_1",
      wrapper: "_wrapper_1cf5l_11",
    }
    

2. 语法

2.1 全局样式

两种写法:

/* 这种写法可以同时暴露多个全局样式块出去 */
:global{
  .a {
    color:rgb(43, 58, 228);
  }
  .b{
    color:rgb(57, 193, 57);
  }
}

/* 等价于 */
:global(.a) {
  color:rgb(41, 193, 201);
}
:global(.b) {
  color:rgb(41, 193, 201);
}

/* 等价于:global(.a){} */
:global .a{
  color:rgb(41, 193, 201);
}
:global .b{
  color:rgb(41, 193, 201);
}
  • 由于CSS Modules不会对非类名选择器进行hash转换。因此非类名选择器也会被暴露到全局。因此存在一些默认的全局样式写法
h1{ //不被css modules处理,若不嵌套直接就是全局样式
  color:red;
}

div[name="custom"] { //不被css modules处理
  color:orange;
}

...

2.3 Class 组合

就是对样式块的复用。

  1. 组合现有样式块
.commonStyle{
  font-size:14px;
  font-weight: 600;
}


.componentA{
  composes:commonStyle;//复用commonStyle

  :global{
    .a{
      color:red;
    }
    .b{
      color:rgb(32, 195, 67);
    }
  }
<div className={styles.componentA}>
  <div className="a">我是内容a</div>
  <div className="b">我是内容b</div>
</div>

组合就是多加了一个转换后的类名到应用该样式的标签上

image.png

2. 组合外部样式块

  • 不一定非得要求为*.modules.less类型的文件
.componentA{
  composes:commonStyle from './commonStyle.less';

  :global{
    .a{
      color:red;
    }
    .b{
      color:rgb(32, 195, 67);
    }
  }

3. 利用:global简化样式隔离方案

先来看常见用法: 将*.module.less文件中所有的类名都通过styles.类名的形式应用。

.componentA{
  color:red;

  .name {
      .desc{
        font-weight: 600;
        color:#333;
      }
  }
}
import styles from './index.module.less';

function App () {
  <div className={styles.componentA}>
  <div className={styles.name}>
      Wei Lang <span className={styles.desc}>good man</span>
  </div>
}

这样做的优缺点:

优点:

  • 所有应用styles.类名的标签上的类名都会被hash转换,都是全局唯一的。

image.png

缺点:

  • 组件中的所有标签都需要使用styles.类名的形式访问,写法繁琐。

每个类名都进行hash转换是否真的有必要?于是有了下面这种写法?

利用:global简化样式隔离方案细节

原理: 只在组件的最外层标签上使用CSS Modules,让其生成唯一类名,组件内部的标签直接使用className声明类名,并在*.module.less文件中将这些类名选择器通过:global{}暴露给全局,此时这样被暴露出来的选择器还是在组件最外层标签的唯一类名下的,所以根本不可能存在冲突问题。

.componentA{
  color:red;

  :global{
    .name {
      .desc{
        font-weight: 600;
        color:#333;
      }
    }
  }
}
import styles from './index.module.less';

function App () {
  <div className={styles.componentA}>
  <div className="name">
      Wei Lang <span className="desc">good man</span>
  </div>
}

image.png

优点:

  • 样式隔离简单,只需要将组件内的标签写在应用styles.类名的样式内部即可。