BEM elment-ui都在使用的css架构

218 阅读2分钟

BEM(Block, Element, Modifier)是一种命名约定,用于编写可维护和可扩展的 CSS 代码。BEM 将代码分为三个部分:块(Block)、元素(Element)和修饰符(Modifier)。以下是 BEM 的基本概念和示例:

基本概念

  1. Block(块):页面中的独立实体,可以是一个组件或一个独立的功能模块。
  2. Element(元素):块的组成部分,不能单独存在,必须依赖于块。
  3. Modifier(修饰符):用于改变块或元素的外观或行为。

命名规则

  • Block.block
  • Element.block__element
  • Modifier.block--modifier.block__element--modifier

示例

假设我们有一个按钮组件:

HTML

<button class="button button--primary">
    <span class="button__text">Click me</span>
</button>

CSS

/* Block */
.button {
    display: inline-block;
    padding: 10px 20px;
    border: none;
    cursor: pointer;
}

/* Element */
.button__text {
    font-size: 16px;
    color: #fff;
}

/* Modifier */
.button--primary {
    background-color: #007bff;
}

详细示例

假设我们有一个卡片组件,包含标题、内容和按钮:

HTML

<div class="card card--highlighted">
    <h2 class="card__title">Card Title</h2>
    <p class="card__content">This is some content inside the card.</p>
    <button class="card__button card__button--primary">Read More</button>
</div>

CSS

/* Block */
.card {
    border: 1px solid #ccc;
    padding: 20px;
    margin: 10px;
    border-radius: 5px;
}

/* Element */
.card__title {
    font-size: 24px;
    margin-bottom: 10px;
}

.card__content {
    font-size: 16px;
    margin-bottom: 20px;
}

.card__button {
    padding: 10px 20px;
    border: none;
    cursor: pointer;
}

/* Modifier */
.card--highlighted {
    border-color: #007bff;
}

.card__button--primary {
    background-color: #007bff;
    color: #fff;
}

总结

BEM 架构通过明确的命名规则,使得 CSS 代码更加清晰、可维护和可扩展。通过将块、元素和修饰符分开,开发者可以更容易地理解和修改代码。

基础规则

$namespace: 'el';
$element-separator: '__';
$modifier-separator: '--';
$state-prefix: 'is-';

@mixin b($block) {
  $B: $namespace+'-'+$block !global;

  .#{$B} {
    @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 + & + $modifier-separator + $unit + ","};
  }

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

案例:简单实现一个计数器

<template>
  <div :class="['sw-input-number', inputNumberSize ? 'sw-input-number--' + inputNumberSize : '']">
    <span class="sw-input-number__decrease" @click="decrease">decrease</span>
    <input class="sw-input-number__input" v-model="num" />
    <span class="sw-input-number__increase" @click="increase">increase</span>
  </div>
</template>
<script lang="ts" setup>
import { defineOptions, defineProps, ref } from 'vue'
defineOptions({
  name: 'InputNumber'
})
const props = defineProps({
  inputNumberSize: {
    type: String,
    default: 'medium'
  }
})
const num = ref(0)
const increase = () => {
  num.value++
}
const decrease = () => {
  num.value--
}
const { inputNumberSize } = props
</script>
<style scoped lang="scss">
@use './inputNumber.scss';
</style>
$namespace: 'sw' !default;
$common-separator: '-' !default;
$element-separator: '__' !default;
$modifier-separator: '--' !default;
$state-prefix: 'is-' !default;
$B: null; // 在样式表的根部声明变量
$E: null; // 在样式表的根部声明变量
$M: null; // 在样式表的根部声明变量
@mixin b($block) {
  $B: $namespace + $common-separator + $block !global;
  .#{$B} {
    @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 + & + $modifier-separator + $unit + ','};
  }

  @at-root {
    #{$currentSelector} {
      @content;
    }
  }
}
@include b(input-number) {
  line-height: 38px;
  display: flex;
  @include e((increase, decrease)) {
    flex: 1;
    line-height: 38px;
    cursor: pointer;
    color: #c0c4cc;
    &:hover {
      color: #606266;
    }
  }
  @include e(decrease) {
    left: 1px;
  }
  @include e(increase) {
    right: 1px;
  }
  @include e(input) {
    flex: 2;
  }
  @include m(medium) {
    width: 200px;
  }
  @include m(small) {
    width: 200px;
  }
}