在前端开发中,组织和管理 CSS 样式是一个常见的挑战。BEM(Block Element Modifier)架构作为一种解决方案,通过一种清晰且易于维护的方式来组织样式代码。它将样式分解为独立的块(Blocks)、元素(Elements)和修饰符(Modifiers),为团队合作和大型项目提供了一致性和可扩展性。然而,随着项目规模的增长和需求的变化,我们需要更灵活和高效的方式来管理样式,这就引入了 Sass(Syntactically Awesome Stylesheets)。Sass 是一种 CSS 预处理器,它为我们提供了许多强大的工具,如变量、嵌套、混合、继承等,使我们能够更加高效地编写和组织 CSS 代码。本文将深入探讨 BEM 架构的原理及其在实际项目中的应用,并结合 Sass 的强大功能,展示如何通过 Sass 实现 BEM 架构,从而使我们的样式代码更具可维护性、可扩展性和重用性。

1.BEM架构概念

Block(块):Block 是一个独立的、可复用的组件或模块,它代表一个完整的功能单元。块是一个顶层的元素,它本身应该有意义并且可以独立存在。
Element(元素):Element 是块的组成部分,它不能单独存在,必须依赖于块。Element 是块的一部分,它只有在块的上下文中才有意义。
Modifier(修饰符):Modifier 是用于改变块或元素外观、状态或行为的标志。通过添加修饰符类名,可以修改块或元素的样式,从而实现不同的变体。
下面以 Element 组件库为例,感受 BEM 架构的用法与规范:

其中 el-tag 代表一个完整的功能单元块,是一个顶层的元素。
el-tag–primary 表示一个修饰符类,primary 代表样式类型。
el-tag__content 表示的是功能单元块下面的一个子类。
由此,BEM 架构约定的命名规范一般为:namespace-block__element–modifier

2.Sass相关

要使用 Sass 来实现 BEM 架构,首先要先对 Sass 的常见语法以及功能有一定的了解。主要涉及有 Sass 的嵌套规则、父选择器、变量、插值语法、混合等。
实现代码如下:

// src/assets/styles/common.scss
// !default 表示这个变量如果没有赋过别的值,默认为 mx(element中为el,可以更换为自己特有的前缀)
$namespace: 'mx' !default;      // 创建一个命名空间,用于定义规范类名的开头
$block-sel: '-' !default;       // 创建一个连接,用于连接块名
$element-sel: '__' !default;        // 创建一个连接,用于连接元素名
$modify-sel: '--' !default;     // 创建一个连接,用于连接标识名

// 创建一个定义 b 的混入,可以生成例如  .mx-bn 的样式
@mixin b($bn) {
    $name: $namespace + $block-sel + $bn;
    .#{$name} {   // 插值语法 即 name 的值
        @content;  // 相当于一个占位符 
    }
}

// 创建一个定义 e 的混入,可以生成例如  .mx-bn__en 的样式
@mixin e($en) {
    $parent: &;  // 获取父级的类名 这里获取的是 .mx-bn
    // @at-root 可以让以下类名的样式跳出父级包裹,例如 .mx-bn .mx-bn__en{} 去除多余的父级选择器变为 .mx-bn__en{}
    @at-root {
    #{$parent + $element-sel + $en} {
            @content;
        }
    }
}

// 创建一个定义 m 的混入,可以生成例如   .mx-bn--mn 的样式
@mixin m($mn) {
    $parent: &;
    @at-root {
        #{$parent + $modify-sel + $mn} {
            @content;
        }
    }
}

3.Vite相关配置

这里以 Vue3 + Vite 项目为例,要将 common.scss 配置为全局通用样式,需要在 vite.config.ts 或 vite.config.js文件中添加 css 配置选项:

export default defineConfig({
  plugins: [vue()],
  css:{
    preprocessorOptions:{
      scss:{
        additionalData:`@import "@/assets/styles/common.scss";`
      }
    }
  }
})

4.BEM架构在项目中的使用

<template>
  <div class="mx-login">
    <p class="mx-login__title">账号登录</p>
    <button class="mx-login--blue">登录</button>
  </div>
</template>
<script lang="ts" setup>

</script>
<style lang="scss">
@include b(login) {  // 对应 mx-login
  height: 300px;
  width: 500px;
  display: flex;
  flex-direction: column;
  align-items: center;
  background-color: #eee;

  @include e(title) {  // 对应 mx-login__title
    font-size: 20px;
    font-weight: 600;
  }

  @include m(blue) {  // 对应 mx-login--blue
    background-color: blue;
  }
}
</style>