夜猫的小站

scss中利用mixin实现bem的写法

Published on
阅读时间:4分钟611

本文最近一次更新于 1429 个天前,其中的内容很可能已经有所发展或是发生改变。

前言

BEM是一种css的命名规范,分别是Block(块)代表更高级别的抽象或组件,Element(元素) Block的后代,以及Modifier(修饰) 不同状态的修饰符,三个单词的缩写,目的是解决css混乱的命名方式,达到一个语义化的CSS命名方式。

命名方法

.block__element--modifier {

}
.block__element {

}
.block--modifier {

}

在预处理语言中的使用示例

.block {
    &__header {
        color: black;
    }
    &__button {
        color: black;
        &--default {
            color: blue
        }
    }
}

scss中结合mixin的bem规范(以element ui为例)

结合sassmeister在线编译

定义mixin

// 定义block的mixin
@mixin b($block) {
  $B: 'el-'+$block !global;
  .#{$B} {
    @content;
  }
}

// 定义element的mixin
@mixin e($element) {
  $E: $element !global;
  $selector: &;
  $currentSelector: "";
  @each $unit in $element {
    $currentSelector: #{$currentSelector + "." + $B + '__' + $unit + ","};
  }

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

// 定义modifier的mixin
@mixin m($modifier) {
  $selector: &;
  $currentSelector: "";
  @each $unit in $modifier {
    $currentSelector: #{$currentSelector + & + '--' + $unit + ","};
  }

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

@at-root指令可以使一个或多个规则被限定输出在文档的根层级上,也就是.parent{ @at-root{.child{}}} 编译以后就是.parent{} .child{}

hitAllSpecialNestRule

@function selectorToString($selector) {
  $selector: inspect($selector);
  $selector: str-slice($selector, 2, -2);
  @return $selector;
}

// 是否包含修饰词
@function containsModifier($selector) {
  $selector: selectorToString($selector);

  @if str-index($selector, $modifier-separator) {
    @return true;
  } @else {
    @return false;
  }
}

// 是否包含.is-前缀
@function containWhenFlag($selector) {
  $selector: selectorToString($selector);

  @if str-index($selector, '.' + 'is-') {
    @return true;
  } @else {
    @return false;
  }
}

// 是否包含":"
@function containPseudoClass($selector) {
  $selector: selectorToString($selector);

  @if str-index($selector, ':') {
    @return true;
  } @else {
    @return false;
  }
}

@function hitAllSpecialNestRule($selector) {

  @return containsModifier($selector) or containWhenFlag($selector) or containPseudoClass($selector);
}

使用mixin

比如element-ui的input样式

@include b(input) {
  position: relative;
  font-size: 12px;
  display: inline-block;
  width: 100%;
  @include e(inner) {
    box-sizing: border-box;
  }
  @include m(small) {
    font-size: 14px;
    @include e(inner) {
      height: 28px;
      line-height: 28px;
    }
  }
}

编译以后就是

.el-input {
    position: relative;
    font-size: 12px;
    display: inline-block;
    width: 100%;
}
.el-input__inner {
    box-sizing: border-box;
}
.el-input--small {
    font-size: 14px;
}
.el-input--small .el-input__inner {
    height: 28px;
    line-height: 28px;
}

扩展element ui的样式

// 首先引用mixin
@import "xxxx/node_modules/element-ui/packages/theme-chalk/src/mixins/mixins";

// 比如说修改默认的弹窗样式
@include b(dialog) {
    @include m(slim) {
        @include e(body) {
            padding: 0 20px 20px;
        }
        @include e(footer){
            padding-top: 0;
        }
    }
}

el-dialog中只需要添加el-dialog--slim样式就能修改弹窗的默认padding了,不过也是采用覆盖的方式。

<el-dialog
    custom-class="el-dialog--slim">
</el-dialog>