CSS样式隔离方案

241 阅读2分钟

问题背景

Vue中scoped 的原理主要是 通过为当前组件的模板添加一个独一无二的属性,然后在 CSS 选择器中添加这个属性,从而实现样式的局部作用域

缺点
  • 样式优先级问题
    • 由于 scoped 通过添加唯一的属性来工作,这会增加选择器的特异性,可能导致由于特异性不同而出现样式优先级问题。例如:通过在父组件中设置样式类,统一控制父子组件的样式。
  • 无法跨组件边界工作
    • scoped 无法控制其他组件的样式,包括子组件。
    • vue 提供了解决方案,可以使用 :deep() 包括需要穿透的类,达到影响子元素的效果。不过若是频繁使用 :deep(),影响代码美观和整洁度是必然的。
  • 性能问题
    • 使用 scoped 可能会导致性能问题,因为浏览器在渲染时必须查找和匹配这些唯一的属性。

解决方案

BEM 命名策略和CSS Module两种方案:

  • BEM 结合工具函数和 scss 预处理函数,可以极大地减轻应用的心智负担,比较典型的 ElementPlus 中就有 BEM 命名策略的应用。

  • CSS Module 我更多的是在 React 项目中使用

BEM 命名策略

什么是 BEM 命名规范

Bem 是块(block)、元素(element)、修饰符(modifier)的简写,由 Yandex 团队提出的一种前端 CSS 命名方法论。

  • 中划线 :仅作为连字符使用,表示某个块或者某个子元素的多单词之间的连接记号。

__ 双下划线:双下划线用来连接块和块的子元素

_ 单下划线:单下划线用来描述一个块或者块的子元素的一种状态

BEM的命名规则

命名约定的模式如下:

.block{}

.block__element{}

.block--modifier{}

BEM解决问题的思路

由于项目开发中,每个组件都是唯一无二的,其名字也是独一无二的,组件内部元素的名字都加上组件名,并用元素的名字作为选择器,自然组件内的样式就不会与组件外的样式冲突了。

BEM的命名规则:block-name__element-name--modifier-name,也就是模块名 + 元素名 + 修饰器名。

element-ui中 BEM 方法的使用

首先来看一个bem命名示例:

.el-message-box{}
.el-message-box__header{}
.el-message-box__header--active{}

如果scss的话,那么可以写成:

.el-message-box {
    &__header' {
        &--active {
        }
    }
}