BEM(Block, Element, Modifier)是一种命名约定,用于编写可维护和可扩展的 CSS 代码。BEM 将代码分为三个部分:块(Block)、元素(Element)和修饰符(Modifier)。以下是 BEM 的基本概念和示例:
基本概念
- Block(块):页面中的独立实体,可以是一个组件或一个独立的功能模块。
- Element(元素):块的组成部分,不能单独存在,必须依赖于块。
- 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;
}
}