Skip to content
On this page

BEM 理论知识点

BEM 架构是什么?

什么是BEM?

BEM 架构是对前端样式命名的规范化,顾名思义,BEM 由 块【block】、元素【element】、修饰符【modifier】组成,其主要作用是方便开发团队对前端项目的样式命名进行统一化处理,加强后期的维护工作。

浅谈 BEM 架构组成

BEM代表 “块(block),元素(element),修饰符(modifier)”,我们常用这三个实体开发组件。

块【block】

  • 块 可以理解为一个作用域标签,附有独立实体的意义,例如我们常常将一个页面的头部命名为 header、内容命名为 content 等等,这在 BEM 架构中采用 - 横杠来连接,常见的有 ElementUI 中用来代表一个表单块的 el-form。

元素【element】

  • 元素 可以理解为 块 中的子项,没有独立实体的意义,但有一定的语义,例如我们常常将一个列表项命名为 item、头部的标题命名为 title 等等,这在 BEM 架构中采用 __ 双下划线来连接,常见的有 ElementUI 中用来代表一个表单项的 el-form__item。

修饰符【modifier】

  • 修饰符 可以理解为 块 或 元素 的一个额外标记,主要用来表示一个特定的外观或行为,例如我们常常用绿色来表示一个成功的提示、黄色来表示一个警告的提示等等,这在 BEM 架构中采用 -- 双横杠来连接,常见的有 ElementUI 中用来代表一个成功的按钮 el-button--success。

BEM命名规则

命名规则

  • [block]
  • [block]__[element]--[modifier]
  • [block]--[modifier]
  • [block]__[element]
  • __ 双下划线用于连接 block 与 element
  • -- 双连字符用于连接 modifier
  • -单连字符用于连接由多单词组成的名字,如.box__goods-image--big

BEM命名的优势

可以获得更多的描述和更加清晰的结构,从其名字可以知道某个标记的含义。通过查看 HTML 代码中的 class 属性,就能知道元素之间的关联。

优势

  • 样式隔离,避免样式污染
  • 代码更容易覆盖
  • 代码易读

应用

  • mixins.scss
css
$namespcae: 'qw' !default;
$block-sel: "-" !default;
$elem-sel: "__" !default;
$mod-sel: "--" !default;

// BEM
@mixin b($block, $selector: "") {
 $B: $namespace + $common-separator + $block !global;

 .#{$B + $selector} {
   @content;
 }
}

@mixin e($element) {
 $E: $element !global;
 $selector: &;
 $currentSelector: "";

 @each $unit in $element {
   $currentSelector: #{$currentSelector +
     "." +
     $B +
     $element-separator +
     $unit +
     ","};
 }

 @if hitAllSpecialNestRule($selector) {
   @at-root {
     #{$selector} {
       #{$currentSelector} {
         @content;
       }
     }
   }
 } @else {
   @at-root {
     #{$currentSelector} {
       @content;
     }
   }
 }
}

@mixin m($modifier) {
 $selector: &;
 $currentSelector: "";

 @each $unit in $modifier {
   $currentSelector: #{$currentSelector +
     $selector +
     $modifier-separator +
     $unit +
     ","};
 }

 @at-root {
   #{$currentSelector} {
     @content;
   }
 }
}

@mixin configurable-m($modifier, $E-flag: false) {
 $selector: &;
 $interpolation: "";

 @if $E-flag {
   $interpolation: $element-separator + $E-flag;
 }

 @at-root {
   #{$selector} {
     .#{$B + $interpolation + $modifier-separator + $modifier} {
       @content;
     }
   }
 }
}

@mixin spec-selector(
 $specSelector: "",
 $element: $E,
 $modifier: false,
 $block: $B
) {
 $modifierCombo: "";

 @if $modifier {
   $modifierCombo: $modifier-separator + $modifier;
 }

 @at-root {
   #{&}#{$specSelector}.#{$block
     + $element-separator
     + $element
     + $modifierCombo
     } {
     @content;
   }
 }
}

@mixin meb($modifier: false, $element: $E, $block: $B) {
 $selector: &;
 $modifierCombo: "";

 @if $modifier {
   $modifierCombo: $modifier-separator + $modifier;
 }

 @at-root {
   #{$selector} {
     .#{$block + $element-separator + $element + $modifierCombo} {
       @content;
     }
   }
 }
}

@mixin when($state) {
 @at-root {
   &.#{$state-prefix + $state} {
     @content;
   }
 }
}

@mixin extend-rule($name) {
 @extend #{"%shared-" + $name} !optional;
}

@mixin share-rule($name) {
 $rule-name: "%shared-" + $name;

 @at-root #{$rule-name} {
   @content;
 }
}

@mixin pseudo($pseudo) {
 @at-root #{&}#{":#{$pseudo}"} {
   @content;
 }
}

@mixin picker-popper($background, $border, $box-shadow) {
 &.#{$namespace}-popper {
   background: $background;
   border: $border;
   box-shadow: $box-shadow;

   .#{$namespace}-popper__arrow {
     &::before {
       border: $border;
     }
   }

   @each $placement,
     $adjacency
       in ("top": "left", "bottom": "right", "left": "bottom", "right": "top")
   {
     &[data-popper-placement^="#{$placement}"] {
       .#{$namespace}-popper__arrow::before {
         border-#{$placement}-color: transparent;
         border-#{$adjacency}-color: transparent;
       }
     }
   }
 }
}
  • tag.scss
css
@use "./mixins/mixins.scss" as *;

@include b(tag) {
  width: 64px;
  height: 29px;
  margin-right: 15px;
  color: #e8f4ff;
  background: #0c2647;
  box-shadow: inset 0px 0px 3px 0px #277cf0;
  border-radius: 6px;
  border: 1px solid #277cf0;

  @include m(success) {
    color: #e8f4ff;
    background: rgba(0, 255, 83, 0.3);
    box-shadow: inset 0px 0px 2px 0px #00ff53;
    border-radius: 6px;
    border: 1px solid #00ff53;
  }

  @include m(info) {
    color: #e8f4ff;
    background: rgba(75, 75, 75, 0.68);
    box-shadow: inset 0px 0px 2px 0px #76b2c9;
    border-radius: 6px;
    border: 1px solid #cacaca;
  }

  @include m(danger) {
    color: #e8f4ff;
    background: rgba(255, 58, 0, 0.52);
    box-shadow: inset 0px 0px 2px 0px #ff3a00;
    border-radius: 6px;
    border: 1px solid #ff3a00;
  }
}