什么是BEM?

BEM(Block Element Modifier)是一种流行的CSS命名规范,由Yandex团队开发。它通过清晰的命名约定来解决CSS作用域和可维护性问题。

核心理念

  • Block(块):独立的、可复用的组件
  • Element(元素):块的组成部分,不能独立存在
  • Modifier(修饰符):改变块或元素外观或行为的标识

命名规则

Block(块)

块是页面的独立组件,可以嵌套但不应相互影响。命名使用小写字母,单词间用连字符分隔。

/* 块的命名 */ .card { } .button { } .menu { } .header { } .search-form { }

Element(元素)

元素是块的组成部分,用双下划线连接。元素必须依附于块存在。

/* 元素的命名 */ .card__title { } .card__content { } .card__footer { } .button__icon { } .button__text { } .menu__item { } .menu__link { }

Modifier(修饰符)

修饰符用于改变块或元素的外观或状态,用双连字符连接。

/* 修饰符的命名 */ .card--featured { } .card--disabled { } .button--primary { } .button--large { } .button--active { } .menu--horizontal { } .menu__item--active { }

HTML结构示例

完整的BEM结构

<!-- 卡片组件 --> <article class="card card--featured"> <header class="card__header"> <h2 class="card__title">文章标题</h2> <time class="card__date">2024-01-01</time> </header> <div class="card__content"> <p class="card__text">文章内容...</p> <img class="card__image" src="image.jpg" alt=""> </div> <footer class="card__footer"> <button class="card__button card__button--primary"> 阅读更多 </button> <button class="card__button card__button--secondary"> 收藏 </button> </footer> </article>

CSS实现示例

/* 基础卡片样式 */ .card { background: white; border-radius: 8px; padding: 20px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } /* 卡片修饰符 */ .card--featured { border: 2px solid #007bff; } .card--disabled { opacity: 0.6; pointer-events: none; } /* 卡片元素 */ .card__header { margin-bottom: 16px; } .card__title { font-size: 1.5rem; font-weight: bold; margin: 0; } .card__date { font-size: 0.875rem; color: #666; } .card__content { margin-bottom: 16px; } .card__text { line-height: 1.6; } .card__image { width: 100%; height: auto; border-radius: 4px; } .card__footer { display: flex; gap: 8px; } .card__button { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; } .card__button--primary { background: #007bff; color: white; } .card__button--secondary { background: #6c757d; color: white; }

BEM的优势

1. 清晰的结构

通过命名就能了解元素的关系和层级,便于团队协作。

2. 避免样式冲突

每个类名都是唯一的,避免了CSS选择器的优先级问题。

3. 提高可维护性

模块化的命名方式使代码更易于理解和修改。

4. 便于复用

组件化的设计使得代码可以在不同项目中复用。

最佳实践

1. 保持简单

不要过度嵌套,保持块的扁平化结构。

2. 避免标签选择器

始终使用类选择器,避免使用标签选择器。

3. 修饰符不要修改结构

修饰符只用于改变外观和行为,不应改变HTML结构。

4. 元素不能独立存在

元素必须依附于块,不要单独使用元素类名。

5. 避免过长的命名

虽然BEM命名可能较长,但要合理控制长度,保持可读性。

常见误区

❌ 错误示例

/* 错误1:元素嵌套过深 */ .card__header__title__text { } /* 错误2:使用标签选择器 */ .card div { } /* 错误3:修饰符改变结构 */ .card--featured .card__header { /* 不应在修饰符中添加新的结构 */ } /* 错误4:元素独立使用 */ .card__title { /* 不应单独使用 */ }

✅ 正确示例

/* 正确1:保持扁平 */ .card__title { } /* 正确2:使用类选择器 */ .card__content { } /* 正确3:修饰符只改变样式 */ .card--featured { border: 2px solid #007bff; } /* 正确4:元素依附于块 */ .card .card__title { }

与其他方法论的对比

方法论 特点 优点 缺点
BEM Block-Element-Modifier 结构清晰,避免冲突 命名较长
OOCSS 面向对象CSS 可复用性强 HTML臃肿
SMACSS 可扩展模块化架构 层次分明 学习曲线陡
Utility-First 工具类优先(如Tailwind) 开发速度快 HTML冗长

实用工具

1. BEM生成器

使用Emmet快速生成BEM结构:

/* Emmet语法 */ .card>.card__header+.card__content+.card__footer /* 展开为 */ <div class="card"> <div class="card__header"></div> <div class="card__content"></div> <div class="card__footer"></div> </div>

2. CSS预处理

使用Sass/Less简化BEM编写:

/* SCSS嵌套语法 */ .card { padding: 20px; &__header { margin-bottom: 16px; } &__title { font-size: 1.5rem; } &--featured { border: 2px solid #007bff; } }

总结

BEM是一种简单而强大的CSS命名规范,它通过清晰的命名约定帮助开发者:

  • 创建可维护的CSS代码
  • 避免样式冲突和优先级问题
  • 提高团队协作效率
  • 构建可复用的组件库

虽然BEM的命名可能显得冗长,但其带来的代码可读性和可维护性优势远超过这个缺点。