首页 > web前端 > css教程 > CSS体系结构:Block-Element-Modifier(BEM)和Atomic CSS

CSS体系结构:Block-Element-Modifier(BEM)和Atomic CSS

尊渡假赌尊渡假赌尊渡假赌
发布: 2025-02-10 10:55:15
原创
385 人浏览过

CSS Architecture: Block-Element-Modifier (BEM) & Atomic CSS

本文节选自Tiffany新书《CSS大师,第二版》。我们将探讨两种CSS命名方法论。这两种方法都是为了改进大型网站和大型团队的开发流程而创建的;然而,它们同样适用于单人团队。您可以选择其中一种、两种都不选,或者混合使用,这取决于您自己。介绍它们的目的是帮助您思考编写自己的CSS的方法。

关键要点

  • BEM(块-元素-修饰符)是一种CSS方法论,它鼓励开发人员将网站视为可重用组件块的集合。它提供了一个清晰的命名系统,使理解网站不同部分之间的关系更容易,对于大型开发团队尤其有利。
  • 相反,原子CSS专注于创建高度细粒度、可重用的样式,而不是为每个组件创建规则集。它减少了特异性冲突,并允许快速HTML组件开发。但是,它更适合小型团队或单个开发人员。
  • BEM和原子CSS可以一起使用,将BEM的结构与原子CSS的可重用性结合起来。这可以产生一个高度组织化和易于维护的CSS代码库。
  • 尽管它们有好处,但在开发人员无法完全控制标记(例如使用CMS)的情况下,BEM和原子CSS可能都没有用。在这种情况下,开发人员可能需要使用冗长且特定的选择器来实现其目标。

块-元素-修饰符(BEM)

BEM,或块-元素-修饰符,是一种方法论、命名系统和一套相关的工具。BEM诞生于Yandex,旨在由大型开发团队进行快速开发。在本节中,我们将重点关注概念和命名系统。BEM方法论鼓励设计师和开发人员将网站视为可重用组件的集合,这些块可以混合和匹配以创建界面。块只是文档的一部分,例如标题、页脚或侧边栏,如下图所示。也许令人困惑的是,“块”在这里指的是构成页面或应用程序的HTML片段。

CSS Architecture: Block-Element-Modifier (BEM) & Atomic CSS

块可以包含其他块。例如,标题块可能还包含徽标、导航和搜索表单块,如下所示。页脚块可能包含站点地图块。

CSS Architecture: Block-Element-Modifier (BEM) & Atomic CSS

比块更细粒度的是元素。正如BEM文档所解释的:

元素是执行特定功能的块的一部分。元素依赖于上下文:它们只有在其所属的块的上下文中才有意义。

例如,搜索表单块包含文本输入元素和提交按钮元素,如下图所示。(为了明确起见,我们使用的是设计元素意义上的“元素”,而不是HTML元素意义上的“元素”。)

CSS Architecture: Block-Element-Modifier (BEM) & Atomic CSS

另一方面,主要内容块可能具有文章列表块。此文章列表块可能包含一系列文章推广块。每个文章推广块可能包含图像、摘录和“阅读更多”元素,如下所示。

CSS Architecture: Block-Element-Modifier (BEM) & Atomic CSS

块和元素共同构成了BEM命名约定的基础。根据BEM规则:

  • 块名称在一个项目中必须唯一
  • 元素名称在一个块中必须唯一
  • 块的变体——例如,具有深色背景的搜索框——应该在类名中添加修饰符

块名称和元素名称通常用双下划线(.block__element)分隔。块和元素名称通常用双连字符与修饰符名称分隔(例如,.block--modifier或.block__element--modifier)。以下是使用搜索表单示例的BEM外观:

<div class="search">
  <label for="s" class="search__label">Search for: </label>
  <input type="text" id="s" class="search__input">
  <button class="search__submit">Search</button>
</div>
登录后复制
登录后复制

具有深色背景的此表单的变体可能使用以下标记:

<div class="search search--inverse">
  <label for="s" class="search__label search__label--inverse">Search for: </label>
  <input type="text" id="s" class="search__input">
  <button class="search__submit search__submit--inverse">Search</button>
</div>
登录后复制
登录后复制

我们的CSS可能如下所示:

.search {
    color: #333;
}
.search--inverse {
    color: #fff;
    background: #333;
}
.search__submit {
    background: #333;
    border: 0;
    color: #fff;
    height: 2rem;
    display: inline-block;
}
.search__submit--inverse {
    color: #333;
    background: #ccc;
}
登录后复制
登录后复制

在我们的标记和CSS中,search--inverse和search__label--inverse是附加的类名。它们不是search和search__label的替代品。类名是BEM系统中使用的唯一选择器类型。可以使用子选择器和后代选择器,但后代也应该是类名。元素和ID选择器是被禁止的。强制执行块和元素名称的唯一性还可以防止命名冲突,这在团队中可能会成为问题。这种方法有几个优点:

  • 新团队成员很容易阅读标记和CSS,并理解其行为
  • 添加更多开发人员可以提高团队生产力
  • 一致的命名减少了类名冲突和副作用的可能性
  • CSS独立于标记
  • CSS高度可重用

BEM的内容远不止本章节中的一节所能容纳的。BEM网站更详细地描述了这种方法,并且还提供了工具和教程来帮助您入门。要了解有关BEM命名约定方面的更多信息,另一个极好的资源是Get BEM。

原子CSS

如果说BEM是行业宠儿,那么原子CSS就是它的叛逆者。雅虎的Thierry Koblentz在其2013年的文章“挑战CSS最佳实践”中命名并解释了原子CSS,它使用一个紧凑的类名库。这些类名通常是缩写的,并且与它们影响的内容脱节。在原子CSS系统中,您可以知道类名是什么作用——但是类名(至少,样式表中使用的类名)和内容类型之间没有关系。让我们用一个例子来说明。以下是我们在所谓的传统CSS架构中可能称之为的一组规则。这些规则集使用描述其应用内容的类名——全局消息框,以及“成功”、“警告”和“错误”消息框的样式:

<div class="search">
  <label for="s" class="search__label">Search for: </label>
  <input type="text" id="s" class="search__input">
  <button class="search__submit">Search</button>
</div>
登录后复制
登录后复制

要创建错误消息框,我们需要将msg和msg-error类名都添加到元素的class属性:

<div class="search search--inverse">
  <label for="s" class="search__label search__label--inverse">Search for: </label>
  <input type="text" id="s" class="search__input">
  <button class="search__submit search__submit--inverse">Search</button>
</div>
登录后复制
登录后复制

让我们将其与原子系统进行对比,在原子系统中,每个声明都成为它自己的类:

.search {
    color: #333;
}
.search--inverse {
    color: #fff;
    background: #333;
}
.search__submit {
    background: #333;
    border: 0;
    color: #fff;
    height: 2rem;
    display: inline-block;
}
.search__submit--inverse {
    color: #333;
    background: #ccc;
}
登录后复制
登录后复制

这是更多的CSS。现在让我们重新创建我们的错误消息组件。使用原子CSS,我们的标记变为:

.msg {
    background-color: #a6d5fa;
    border: 2px solid #2196f3;
    border-radius: 10px;
    font-family: sans-serif;
    padding: 10px;
}
.msg-success {
    background-color: #aedbaf;
    border: 2px solid #4caf50;
}
.msg-warning {
    background-color: #ffe8a5;
    border-color:  #ffc107;
}
.msg-error {
    background-color: #faaaa4;
    border-color: #f44336;
}
登录后复制

我们的标记也更冗长。但是当我们创建警告消息组件时会发生什么?

<p class="msg msg-error">An error occurred.</p>
登录后复制

两个类名发生了变化:bg-d和bc-d被bg-c和bc-c替换。我们重用了五个规则集。现在,让我们创建一个按钮:

.bg-a {
    background-color: #a6d5fa;
}
.bg-b {
    background-color: #aedbaf;
}
.bg-c {
    background-color: #ffe8a5;
}
.bg-d {
    background-color: #faaaa4;
}
.bc-a{
    border-color: #2196f3;
}
.bc-b {
    border-color: #4caf50;
}
.bc-c {
    border-color:  #ffc107;
}
.bc-d {
    border-color:  #f44336;
}
.br-1x {
    border-radius: 10px;
}
.bw-2x {
    border-width: 2px;
}
.bss {
    border-style: solid;
}
.sans {
    font-style: sans-serif;
}
.p-1x {
    padding: 10px;
}
登录后复制

嘿!在这里,我们重用了四个规则集,并且避免向我们的样式表中添加更多规则。在一个强大的原子CSS架构中,添加新的HTML组件(例如文章侧边栏)不需要添加更多CSS(尽管实际上,它可能需要添加更多内容)。原子CSS有点像在CSS中使用实用程序类,但达到了极致。具体来说,它:

  • 通过创建高度细粒度、高度可重用的样式来保持CSS简洁,而不是为每个组件创建规则集
  • 通过使用低特异性选择器系统来大大减少特异性冲突
  • 一旦定义了初始规则集,就可以进行快速的HTML组件开发

但是,原子CSS并非没有争议。

反对原子CSS的论点

原子CSS与我们学习的几乎所有关于编写CSS的内容都背道而驰。它感觉几乎和到处粘贴样式属性一样糟糕。事实上,对原子CSS方法论的主要批评之一是它模糊了内容和演示之间的界限。如果将元素浮动到左侧并添加十像素的边距,当我们不再希望该元素浮动到左侧时该怎么办?当然,一个答案是将fl类从我们的元素中删除。但是现在我们正在更改HTML。使用CSS的全部原因是为了使标记不受演示的影响,反之亦然。(我们也可以通过从样式表中删除.fl {float: left;}规则来解决此问题,尽管这会影响每个类名为fl的元素。)尽管如此,更新HTML可能是为了获得更简洁的CSS而付出的少量代价。在Koblentz的原始文章中,他使用了诸如.M-10(margin: 10px)和.P-10(padding: 10px)之类的类名。这种命名约定的问题应该很明显。更改为五像素或20像素的边距意味着我们需要更新我们的CSSHTML,否则可能会导致类名无法准确描述其效果。使用诸如p-1x之类的类名,如本节所述,解决了这个问题。类名中的1x部分表示比率,而不是定义的像素数。如果基本填充是五像素(即,.p-1x { padding: 5px; }),则.p-2x将设置十像素的填充。是的,这不太能描述类名所做的工作,但这同时也意味着我们可以更改CSS而无需更新HTML,并且不会创建误导性的类名。原子CSS架构不会阻止我们使用描述内容的类名在我们的标记中。您仍然可以向代码中添加.button-close或.accordion-trigger。对于JavaScript和DOM操作,此类类名实际上更可取。

BEM与原子CSS

当您有大量开发人员并行构建CSS和HTML模块时,BEM效果最佳。它有助于防止大型团队创建的错误和bug。它可以很好地扩展,部分原因是命名约定具有描述性和可预测性。BEM不仅仅适用于大型团队,但它非常适合大型团队。当有一个小型团队或一名工程师负责开发一组CSS规则,并由一个更大的团队构建完整的HTML组件时,原子CSS效果更好。使用原子CSS,开发人员只需查看样式指南——或CSS源代码——即可确定特定模块所需的类名集。

了解何时走自己的路

在实践中,您的CSS可能包含多种方法的混合。除了影响布局的实用程序类名之外,您可能还有一些描述内容或组件的类名。如果您无法完全控制标记(例如使用CMS),那么这两种方法都可能没有用。您甚至可能需要使用冗长且特定的选择器来实现您想要的目标。

关于CSS架构的常见问题解答:BEM和原子CSS

BEM和原子CSS的主要区别是什么?

BEM(块、元素、修饰符)和原子CSS都是组织和构建CSS代码的方法论。BEM专注于一种命名约定,使CSS更容易阅读和理解。它将设计划分为块、元素和修饰符,以在CSS和HTML之间创建清晰、严格的关系。另一方面,原子CSS是关于编写反映视觉功能的小型、单一用途的CSS类。它鼓励可重用性并旨在减少代码量。

BEM如何提高CSS的可扩展性?

BEM通过在CSS和HTML之间提供清晰而严格的关系来提高CSS的可扩展性。它使用特定的命名约定,使理解不同元素之间的关系更容易。这使得代码更易于维护和扩展,因为更容易添加新功能或修改现有功能而不会破坏任何东西。

我可以同时使用BEM和原子CSS吗?

是的,可以同时使用BEM和原子CSS。一些开发人员发现,结合这两种方法可以获得两全其美的好处。BEM的严格命名约定可用于构建CSS,而原子CSS的单一用途类可用于设置单个元素的样式。这种组合可以产生高度组织化和易于维护的CSS代码库。

使用原子CSS的好处是什么?

原子CSS提供了许多好处。它鼓励可重用性,这可以大大减少您需要编写的CSS数量。它还提高了设计的一致性,因为相同的类用于不同的组件。此外,原子CSS可以使您的样式表更易于管理和理解,因为每个类都有一个单一、明确定义的目的。

BEM如何处理CSS特异性问题?

BEM通过鼓励开发人员使用类选择器而不是ID选择器来帮助处理CSS特异性问题。这导致整个项目中的特异性保持一致,因此在必要时更容易覆盖样式。此外,BEM的命名约定清楚地表明哪些元素是相关的,从而减少了意外样式冲突的可能性。

原子CSS适用于大型项目吗?

是的,原子CSS适用于大型项目。它对可重用性和单一用途类的关注可以帮助保持CSS的可管理性,即使项目不断发展壮大。但是,它需要一种严谨的方法来确保类保持一致和有意义。

BEM如何在团队协作中提供帮助?

BEM清晰而严格的命名约定使团队成员更容易理解CSS代码,无论他们何时加入项目。这可以改善协作,因为开发人员可以轻松理解和修改其他人编写的代码。

使用原子CSS的潜在缺点是什么?

原子CSS的一个潜在缺点是它可能导致HTML中出现大量类。这可能使HTML更难阅读和理解。此外,原子CSS需要一种严谨的方法来确保类保持一致和有意义。

如何在我的项目中开始实现BEM?

要开始实现BEM,您需要将设计划分为块、元素和修饰符。然后,使用BEM的命名约定来命名您的CSS类。这将在您的CSS和HTML之间创建清晰的关系,使您的代码更易于阅读和维护。

我可以将BEM或原子CSS与Sass或Less等CSS预处理器一起使用吗?

是的,BEM和原子CSS都可以与Sass或Less等CSS预处理器一起使用。这些预处理器可以使管理CSS更容易,并且它们与BEM和原子CSS的组织原则非常契合。

以上是CSS体系结构:Block-Element-Modifier(BEM)和Atomic CSS的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板