[小Tip] CSS Modules 提升优先级的一种方式 :not(.xxx)

144 阅读2分钟

CSS Modules 通过以模块化的方式编写 CSS 代码,在 JavaScript 文件中导入和使用,自动生成唯一的类名,隔离样式,避免类名冲突。

style.module.scss

.more {
  &List {
    &Btn {
      &:hover {
        background: #fff;
      }
    }
  }
}

index.tsx

import styles from './style.module.scss'

<Button className={styles.moreListBtn}></Button>

开发时生成的类名就长这样:

.__src_views_xxx_module__moreListBtn-a7f49f:hover {
  background: #fff;
}

一般都是生成一个类名。

一个类名可能就会遇到优先级低无法覆盖样式的问题,比如Button就有这样一个外部样式:

@media (hover: hover) {
    button.Btn:hover:not(.Btn--primary):not(.Btn--outline):not(:disabled) {
        background: rgba(0, 0, 0, .04);
    }
}

显然上面 CSS Modules 生成的样式优先级低于外部样式,自定义样式就不会生效。

!important 是不推荐的,MDN 也说了:使用 !important 是一个坏习惯,应该尽量避免,因为这破坏了样式表中的固有的级联规则 使得调试找 bug 变得更加困难了。

先复习下 CSS 优先级:

下面列表中,选择器类型的优先级是递增的:

  1. 类型选择器:(例如,h1)和伪元素(例如,::before
  2. 类选择器:(例如,.example),属性选择器(例如,[type="radio"])和伪类(例如,:hover
  3. ID 选择器:(例如,#example)。

通配选择器(*)、关系选择器(+、>、~、" "、||)和 否定伪类(:not())对优先级没有影响。(但是,在 :not() 内部声明的选择器会影响优先级)。

ID 选择器 在 CSS Modules 中通常不建议使用。那么可以通过添加类选择器提升优先级。

@media (hover: hover) {
    button.Btn:hover:not(.Btn--primary):not(.Btn--outline):not(:disabled) {
        background: rgba(0, 0, 0, .04);
    }
}

上面这段 CSS 的优先级是 051,即 0ID 选择器5类选择器1类型选择器

.__src_views_xxx_module__moreListBtn-a7f49f:hover {
  background: #fff;
}

对于 <Button className={styles.moreListBtn}></Button>,生成的类名只有2个类选择器,需要添加4个类选择器使优先级达到 061 就可以覆盖外部样式。

那么如何添加类选择器又不会影响 CSS Modules 的使用呢,这时就可以通过否定伪类(:not())添加凑数类名,既可以增加类选择器提升优先级,又不会影响 CSS Modules 的使用。

.more {
  &List {
    &Btn:not(.priority1):not(.priority2):not(.priority3):not(.priority4) {
      &:hover {
        background: #fff;
      }
    }
  }
}

生成的类名如下:

.__src_views_xxx_module__moreListBtn-a7f49f:not(
    .__src_views_xxx_module__priority1-a7f49f
  ):not(
    .__src_views_xxx_module__priority2-a7f49f
  ):not(
    .__src_views_xxx_module__priority3-a7f49f
  ):not(
    .__src_views_xxx_module__priority4-a7f49f
  ):hover {
  background: #fff;
}

这样就有6个类选择器了。