BEM规范
Block Element Modifier - CSS命名规范方法论
什么是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的命名可能显得冗长,但其带来的代码可读性和可维护性优势远超过这个缺点。