BEM命名规范

在前端开发中,随着项目规模的扩大,CSS代码的组织和维护变得越来越具有挑战性。开发者常常面临类名冲突、样式覆盖、代码难以维护等问题。为了解决这些问题,各种CSS命名规范和方法论应运而生,而BEM(Block-Element-Modifier)作为其中最流行和实用的方法之一,被越来越多的开发团队所采用。

1、什么是BEM规范

BEM全称:“Block Element Modifier”,意思是:“块、元素、修饰符”,意思是任意CSS命名都可以按照上述三类进行命名。

但是除了上述块、元素、修饰符以外,其实还有一类“State”表示“状态”,所以我更愿意叫“BEMS”而不是“BEM”。

2、BEM的三个核心概念

2.1 Block(块)

Block是一个独立的组件,可以在项目中重复使用,且不依赖于页面上的其他组件。

  • 命名规则:使用小写字母,多个单词之间用连字符(-)连接。

示例:

.header {}
.menu {}
.search-form {}

2.2 Element(元素)

Element是Block的组成部分,不能脱离Block单独使用。

  • 命名规则:Block名称 + 双下划线(__)+ Element名称。

示例:

.menu__item {}
.search-form__input {}
.header__logo {}
按钮文字(btn__text)
卡片标题(card__title)

2.3 Modifier(修饰符)

Modifier用于定义Block或Element的外观、状态或行为。

命名规则:

  • 对于Block的修饰:Block名称 + 双连字符(--)+ Modifier名称
  • 对于Element的修饰:Block名称__Element名称 + 双连字符(--)+ Modifier名称

示例:

/* Block修饰符 */
.menu--fixed {}
.button--large {}

/* Element修饰符 */
.menu__item--active {}
.search-form__input--disabled {}
按钮尺寸(btn--large)
卡片标题颜色(card__title--warning)

2.4 State状态

  • 命名符:“is”、“has”、“-”(短横线)
  • 命名格式:is-state / has-property
  • 作用:通用状态类,允许跨块复用
  • 示例场景:禁用状态(is-disabled)、含有未读属性(has-unread)

3、为什么要用BEM

使用BEM无非就是两点:

  • BEM命名更加工整,他人阅读代码更加方便,一目了然
  • 在某些情况下(如vue组件封装),可以防止作用域冲突

对于第一点就不再多说,着重说明第二点,我们假设有“App.vue”和“child.vue”两个vue文件,其中App.vue是父组件,child.vue是子组件,具体代码如下:

App.vue:

<script setup>
import child from './views/child.vue';
</script>
 
<template>
  <div class="container">
    <div class="title">
      <span>这是父组件区域</span>
    </div>
    <div class="content">
      <child />
    </div>
  </div>
</template>
 
<style scoped>
.container {
	width: 100%;
	height: 100%;
	color: red;
	background-color: blueviolet;
}
.container .title {
    font-size: 20px;
    font-weight: bold;
    color: black;
}
</style>

child.vue:

<script setup>
 
</script>
 
<template>
<div class="container">
    <div class="title">这是子组件区域</div>
</div>
</template>
 
<style scoped>
.container {
    background-color: white;
    color: green;
}
.container .title {
    color: orange;
}
</style>

效果:
在这里插入图片描述
此时子组件的container明明是白色的背景为什么还会是紫色的呢?

我们打开F12开发者工具发现:
在这里插入图片描述
在这里插入图片描述
子组件的container居然被父组件的container顶掉了,官方给出的结论是:

  • 子组件的根元素会继承父组件的所有样式

为此,使用BEM命名可以有效的避免子组件的CSS与父组件的CSS重名。

4、BEM示例

4.1 基本示例

以一个简单的导航菜单为例:

<nav class="nav">
  <ul class="nav__list">
    <li class="nav__item">
      <a href="#" class="nav__link nav__link--active">首页</a>
    </li>
    <li class="nav__item">
      <a href="#" class="nav__link">关于我们</a>
    </li>
    <li class="nav__item">
      <a href="#" class="nav__link">服务</a>
    </li>
    <li class="nav__item">
      <a href="#" class="nav__link">联系我们</a>
    </li>
  </ul>
</nav>

对应的CSS:

.nav {
  background-color: #333;
  padding: 10px;
}

.nav__list {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav__item {
  margin-right: 20px;
}

.nav__link {
  color: white;
  text-decoration: none;
}

.nav__link--active {
  font-weight: bold;
  border-bottom: 2px solid white;
}

4.2 复杂示例

对于更复杂的组件,如一个带有标题、内容和操作按钮的卡片:

<div class="card">
  <div class="card__header">
    <h2 class="card__title">文章标题</h2>
    <span class="card__date">2023-05-15</span>
  </div>
  <div class="card__content">
    <p class="card__text">这是文章的内容...</p>
    <img class="card__image" src="image.jpg" alt="图片描述">
  </div>
  <div class="card__footer">
    <button class="card__button card__button--primary">阅读更多</button>
    <button class="card__button card__button--secondary">分享</button>
  </div>
</div>

对应的CSS:

.card {
  border: 1px solid #ddd;
  border-radius: 4px;
  overflow: hidden;
  margin-bottom: 20px;
}

.card__header {
  padding: 15px;
  background-color: #f5f5f5;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.card__title {
  margin: 0;
  font-size: 18px;
}

.card__date {
  color: #666;
  font-size: 14px;
}

.card__content {
  padding: 15px;
}

.card__text {
  margin-top: 0;
}

.card__image {
  max-width: 100%;
  height: auto;
  margin-top: 10px;
}

.card__footer {
  padding: 15px;
  background-color: #f5f5f5;
  display: flex;
  justify-content: flex-end;
}

.card__button {
  padding: 8px 15px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  margin-left: 10px;
}

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

.card__button--secondary {
  background-color: #6c757d;
  color: white;
}

5、BEM的常见问题与解决方案

5.1 类名过长

当项目结构复杂时,BEM类名可能会变得很长,影响代码的可读性。

解决方案:

  • 使用简短但有意义的Block和Element名称
  • 考虑使用预处理器(如SASS或LESS)的嵌套功能来简化编写
    • 在SASS/SCSS中,&符号表示父选择器的引用,可以大大简化BEM风格的CSS编写:
.card {
  &__header { /* .card__header */ }
  &__title { /* .card__title */ }

  &__button {
    /* .card__button */
    &--primary { /* .card__button--primary */ }
    &--secondary { /* .card__button--secondary */ }
  }
}

5.2 嵌套元素的命名

当元素嵌套层级较深时,可能会出现命名困难的情况。

解决方案:BEM不推荐反映DOM结构的类名,如.block__elem1__elem2。应该始终保持扁平的命名结构:.block__elem1和.block__elem2。

<!-- 不推荐 -->
<div class="card">
  <div class="card__content">
    <div class="card__content__section">...</div>
  </div>
</div>

<!-- 推荐 -->
<div class="card">
  <div class="card__content">
    <div class="card__section">...</div>
  </div>
</div>

5.3 何时创建新的Block

有时候很难判断应该创建一个新的Block还是继续使用Element。

判断标准:如果一个组件可以在不同的上下文中独立使用,那么它应该是一个Block;如果它只在特定Block中使用,那么它应该是一个Element。

6、总结

BEM命名规范是一种强大的CSS组织方法,它通过明确的命名约定,帮助开发者创建模块化、可维护的CSS代码。虽然在某些情况下类名可能会变得冗长,但其带来的代码清晰度和维护性的提升远远超过了这一小缺点。无论是小型项目还是大型应用,采用BEM命名规范都能帮助你构建更加健壮和可扩展的前端代码结构。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

太阳与星辰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值