BEM 初学者:为什么需要 BEM

已发表: 2022-03-10
快速总结 ↬ CSS 样式隔离是 BEM 使用最常见的起点。 但这是 BEM 能给你的最少的东西。 BEM 在您的项目中引入了一种系统方法,并使其远离混乱。

BEM 使您的代码可扩展和可重用,从而提高生产力并促进团队合作。 即使您是团队中唯一的成员,BEM 也可能对您有用。 然而,许多开发人员认为,像 BEM 这样的系统方法给他们的项目增加了额外的界限,并使您的项目超载、繁琐和缓慢。

我们将以浓缩的形式收集 BEM 的所有主要方面。 本文帮助您在短短 20 分钟内了解 BEM 的基本思想,并摒弃系统方法对您的项目有害的偏见。

Big BEM 由方法技术工具组成。 在本文中,我们将更多地讨论方法论本身,因为它是大量开发人员的集中经验,它为任何项目带来了系统化的方法。

为了向您展示 BEM 的一些实际案例,我们将涉及 BEM 技术并完全跳过库和工具。

从理论到实践:

  • 我们不使用除类之外的任何选择器的主要原因
  • BEM的基础知识
    • 块和元素
    • 修饰符和混合
    • 文件结构中的块
  • 方法论的非明显优势
  • 实际案例:BEM 不仅仅适用于 CSS
  • BEM 是一个可定制的系统

那么,BEM是英雄还是恶棍? 由你决定! 但首先,请阅读文章。

BEM 作为蝙蝠侠的标志
BEM蝙蝠侠
跳跃后更多! 继续往下看↓

我们不使用除类之外的任何选择器的主要原因

BEM 方法的基本规则之一是只使用类选择器。 在本节中,我们将解释原因。

  • 为什么我们不使用 ID?
  • 为什么我们不使用标签选择器?
  • 为什么我们不使用通用选择器?
  • 为什么我们不使用 CSS 重置?
  • 为什么我们不使用嵌套选择器?
  • 为什么我们不在选择器中结合标签和类呢?
  • 为什么我们不使用组合选择器-
  • 为什么我们不使用属性选择器?

我们不使用 ID(ID 选择器)

ID 为 HTML 元素提供了一个唯一的名称。 如果名称是唯一的,则不能在界面中重复使用它。 这可以防止您重用代码。

常见的误解

  1. 使用 JavaScript 需要 ID。
    现代浏览器可以使用 ID 或类。 任何类型的选择器在浏览器中都以相同的速率进行处理。
  2. ID 与<label>标记一起使用。
    如果将<label>放在控件中,则不需要 ID。 而不是<input id="ID"><label for="ID">Text</label> ,只需使用<label><input type="...">Text</label>

我们不使用标签选择器

HTML 页面标记不稳定:新设计可以更改部分的嵌套、标题级别(例如,从<h1><h3> )或将<p>段落转换为<div>标记。 任何这些更改都会破坏为标签编写的样式。 即使设计没有改变,标签集也是有限的。 要在另一个项目中使用现有布局,您必须解决为相同标签编写的样式之间的冲突。

一组扩展的语义标签也不能满足所有的布局需求。

例如,当页眉包含徽标时。 单击徽标会打开网站的主页( index )。 您可以使用标签来标记它,方法是使用图像的<img>标记和链接的<a>标记。

 <header> <a href="/"> <img src="img.logo.png" alt="Logo"> </a> </header>

要区分标志链接和文本中的普通链接,您需要额外的样式。 现在从徽标链接中删除下划线和蓝色:

 header a { ... }

徽标链接不需要显示在主页上,因此更改索引页面标记:

 <header> <!-- the <a> tag is replaced with <span> --> <span> <img src="img.logo.png" alt="Logo"> </span> </header>

您不需要删除<span>标记的下划线和蓝色。 因此,让我们为来自不同页面的徽标链接制定一般规则:

 header a, header span { ... }

乍一看,这段代码似乎没问题,但想象一下如果设计师从布局中删除了徽标。 选择器名称无法帮助您了解应从带有徽标的项目中删除哪些样式。 “header a”选择器不显示链接和徽标之间的连接。 该选择器可以属于标题菜单中的链接,或者,例如,属于作者个人资料的链接。 “标题跨度”选择器可以属于标题的任何部分。

为避免混淆,只需使用logo类选择器来编写徽标样式:

 .logo { ... }

我们不使用 CSS 重置

CSS 重置是为整个页面创建的一组全局 CSS 规则。 这些样式影响所有的布局节点,违反了组件的独立性,并且更难重用它们。

在 BEM 中,“reset”和“normalize”甚至不用于单个块。 重置和规范化会取消现有样式并用其他样式替换它们,无论如何您都必须稍后更改和更新。 结果,开发人员必须编写样式来覆盖刚刚重置的样式。

我们不使用通用选择器 ( * )

通用选择器表示项目具有影响布局中所有节点的样式。 这限制了布局在其他项目中的重用:

  • 您必须另外将带有星号的样式转移到项目中。 但在这种情况下,通用选择器可能会影响新项目中的样式。
  • 带有星号的样式必须添加到您正在传输的布局中。

此外,通用选择器可以使项目代码不可预测。 例如,它会影响通用库组件的样式。

常见的样式并不能节省您的时间。 通常,开发人员首先会重置组件的所有边距( * { margin: 0; padding: 0; } ),但随后他们仍然将它们设置为与布局中相同(例如, margin: 12px; padding: 30px; )。

我们不使用嵌套选择器

嵌套选择器增加了代码耦合,使代码难以重用。

BEM 方法不禁止嵌套选择器,但建议不要过多使用它们。 例如,如果您需要根据块的状态或其分配的主题更改元素的样式,则嵌套是合适的。

 .button_hovered .button__text { text-decoration: underline; } .button_theme_islands .button__text { line-height: 1.5; }

我们不使用组合选择器

组合选择器比单个选择器更具体,这使得重新定义块更加困难。

考虑以下代码:

 <button class="button button_theme_islands">...</button>

假设您在.button.button_theme_islands选择器中设置 CSS 规则以减少编写工作。 然后将“active”修饰符添加到块中:

 <button class="button button_theme_islands button_active">...</button>

.button_active选择器不会重新定义编写为.button.button_theme_islands的块属性,因为.button.button_theme_islands.button_active更具体。 要重新定义它,请将块修饰符选择器与.button选择器结合起来,并在.button.button_theme_islands下方声明它,因为这两个选择器同样具体:

 .button.button_theme_islands {} .button.button_active {}

如果您使用简单的类选择器,则重新定义样式不会有问题:

 .button_theme_islands {} .button_active {} .button {}

我们不会在选择器中组合标签和类

在同一个选择器中组合标签和类(例如button.button )使 CSS 规则更加具体,因此更难重新定义它们。

考虑以下代码:

 <button class="button">...</button>

假设您在button.button选择器中设置 CSS 规则。 然后将active修饰符添加到块中:

 <button class="button button_active">...</button>

.button_active选择器不会重新定义编写为button.button的块属性,因为button.button.button_active更具体。 为了使其更具体,您应该将块修饰符选择器与button.button_active标签结合起来。

随着项目的发展,您最终可能会得到带有input.buttonspan.buttona.button选择器的块。 在这种情况下, button块的所有修饰符及其所有嵌套元素都需要针对每个实例进行四种不同的声明。

可能的例外

在极少数情况下,该方法允许组合标签和类选择器。 例如,这可用于在无法生成正确布局的 CMS 系统中设置评论样式。

您可以使用注释来编写文本、插入图像或添加标记。 为了使它们与网站设计相匹配,开发人员可以为用户可用的所有标签预定义样式并将它们级联到嵌套块:

 <div class="content"> ... <!-- the user's text --> </div> CSS rules: .content a { ... } .content p { font-family: Arial, sans-serif; text-align: center; }

我们不使用属性选择器

属性选择器比类选择器提供的信息更少。 作为证明,考虑一个在标题中包含搜索表单的示例:

 <header> <form action="/"> <input name="s"> <input type="submit"> </form> </header>

尝试使用选择器属性来编写表单样式:

 header input[type=submit], header input[type=checkbox] { width: auto; margin-right: 20px; } header input[type=checkbox] { margin: 0; }

在此示例中,您无法从选择器名称中确定样式属于搜索表单。 使用类使其更清晰。 课程没有限制你写得很清楚。 例如,你可以这样写:

 .form .search { ... }

现在代码没有歧义了,很明显样式属于搜索表单。

但是嵌套选择器仍然使 CSS 规则更加具体,并阻止您在项目之间转移布局。 要摆脱嵌套,请使用 BEM 原则。

总结class是唯一可以让你隔离项目中各个组件的样式的选择器; 增加代码的可读性并且不限制布局的重用。

CSS 样式隔离是 BEM 旅程最常见的起点。 但这是 BEM 能给你的最少的东西。 要了解 BEM 中孤立的独立组件是如何排列的,您需要学习基本概念,即块、元素、修饰符和混合。 让我们在下一节中执行此操作。

BEM的基础知识

  • 块和元素
  • 修饰符和混合
  • 文件结构中的块

块和元素

BEM 方法是一组通用规则,无论使用何种技术,例如 CSS、Sass、HTML、JavaScript 或 React,都可以应用这些规则。

BEM 有助于解决以下任务:

  • 重用布局;
  • 在项目中安全地移动布局片段;
  • 在项目之间移动完成的布局;
  • 创建稳定、可预测和清晰的代码;
  • 减少项目调试时间。

在 BEM 项目中,界面由可以包含元素的块组成。 块是页面的独立组件。 元素不能存在于块之外,因此请记住每个元素只能属于一个块。

BEM 中的前两个字母代表B锁和元素。 块名称始终是唯一的。 它为元素设置命名空间并提供块部件之间的可见连接。 块名称很长但清晰,以便显示组件之间的连接并避免在传输布局时丢失这些组件的任何部分。

要了解 BEM 命名的全部功能,请考虑这个带有表单的示例。 根据 BEM 方法,表单是使用form块实现的。 在 HTML 中,块名称包含在class属性中:

 <form class="form" action="/">

表单中没有意义的所有部分( form块)都被视为其元素。 所以搜索框( search )和按钮( submit )是form块的元素。 类还表明一个元素属于该块:

 <form class="form" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>

请注意,块的名称与元素的名称使用特殊的分隔符分隔。 在 BEM 经典命名方案中,使用两个下划线作为分隔符。 任何东西都可以作为分隔符。 还有其他命名约定,每个开发人员都会选择适合他们的命名约定。 重要的是分隔符允许您以编程方式将块与元素和修饰符区分开来。

选择器名称清楚地表明,为了将表单移动到另一个项目,您需要复制其所有组件:

 .form__search {} .form__submit {}

使用块和元素作为类名解决了一个重要问题:它帮助我们摆脱了嵌套选择器。 BEM 项目中的所有选择器具有相同的权重。 这意味着重新定义根据 BEM 编写的样式要容易得多。 现在,要在另一个项目中使用相同的表单,您只需复制其布局和样式即可。

BEM 组件命名的想法是您可以显式定义块与其元素之间的连接。

修饰符和混合

官方上,“M”代表M修饰符,但它也暗示了 BEM 中一个更重要的概念:“混合”。 修饰符和混合都会对块及其元素进行更改。 让我们仔细看看这个。

修饰符

修饰符定义块或元素的外观、状态和行为。 添加修饰符是可选的。 修改器允许您组合不同的块功能,因为您可以使用任意数量的修改器。 但是不能为块或元素分配相同修饰符的不同值。

让我们探索修饰符是如何工作的。

想象一下,该项目需要与上面示例中相同的搜索表单。 它应该具有相同的功能但看起来不同(例如,页眉和页脚中的搜索表单应该不同)。 改变表单外观的第一件事是编写额外的样式:

 header .form {} footer .form {}

header .form选择器比form选择器具有更大的权重,这意味着一条规则将覆盖另一条规则。 但正如我们所讨论的,嵌套选择器增加了代码耦合,使重用变得困难,所以这种方法对我们不起作用。

在 BEM 中,您可以使用修饰符将新样式添加到块中:

 <!-- Added the form_type_original modifier--> <form class="form form_type_original" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>

<form class="form form_type_original"></form>行表示该块被分配了具有original值的type修饰符。 在经典方案中,修饰符名称与块或元素名称用下划线分隔。

表单可以具有独特的颜色、大小、类型或设计主题。 所有这些参数都可以使用修饰符设置:

 <form class="form form_type_original form_size_m form_theme_forest"> <form class="form form_type_original form_size_m form_theme_forest">

相同的表格可以看起来不同但尺寸保持不变:

 <form class="form form_type_original form_size_m form_theme_forest"></form> <form class="form form_type_original form_size_m form_theme_sun"></form>

但是每个修饰符的选择器仍然具有相同的权重:

 .form_type_original {} .form_size_m {} .form_theme_forest {}

重要提示修饰符仅包含以某种方式更改原始块实现的附加样式。 这允许您只设置一次通用块的外观,并且仅将与原始块代码不同的那些功能添加到修饰符样式中。

 .form { /* universal block styles */ } .form_type_original { /* added styles */ }

这就是为什么修饰符应该始终与块及其关联的元素位于同一个 DOM 节点上的原因。

 <form class="form form_type_original"></form>

在非常特殊的情况下,您可以使用修饰符来应用通用组件。 块和元素代码不会改变。 在 DOM 节点上创建必要的修饰符组合。

混音

混合允许您将相同的格式应用于不同的 HTML 元素,并结合多个实体的行为和样式,同时避免代码重复。 它们可以替换抽象包装块。

混合意味着您在单个 DOM 节点上托管多个 BEM 实体(块、元素、修饰符)。 与修改器类似,混合用于更改块。 让我们看一些什么时候应该使用混音的例子。

块不仅可以在视觉上而且在语义上也可以不同。 例如,搜索表单、注册表单和订购蛋糕的表单都是表单。 在布局中,它们是用“表单”块实现的,但它们没有任何共同的样式。 用修饰符处理这种差异是不可能的。 您可以为此类块定义通用样式,但您将无法重用代码。

 .form, .search, .register { ... }

您可以使用混合为同一表单创建语义不同的块:

 <form class="form" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>

.form类选择器描述了可以应用于任何表单(订单、搜索或注册)的所有样式:

 .form {}

现在您可以从通用表单中创建一个搜索表单。 为此,请在项目中创建一个额外的search类。 这个类将只负责搜索。 要组合.form.search类的样式和行为,请将这些类放在一个 DOM 节点上:

 <form class="form search" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>

在这种情况下, .search类是定义行为的单独块。 这个块不能有负责形式、主题和大小的修饰符。 这些修饰语已经属于通用形式。 混合有助于组合这些块的样式和行为。

让我们再举一个组件的语义发生变化的例子。 这是页眉中的导航菜单,其中所有条目都是链接:

 <nav class="menu"> <a class="link" href=""></a> <a class="link" href=""></a> <a class="link" href=""></a> </nav>

链接功能已在link块中实现,但菜单链接必须在视觉上与文本中的链接不同。 有几种方法可以更改菜单链接:

  1. 创建一个菜单条目修饰符,将条目转换为链接:
     <nav class="menu"> <a class="menu__item menu__item_link" href=""></a> <a class="menu__item menu__item_link" href=""></a> <a class="menu__item menu__item_link" href=""></a> </nav>

    在这种情况下,要实现修饰符,您应该复制 `link` 块的行为和样式。 这将导致代码重复。
  2. 混合使用 `link` 通用块和 `menu` 块的 `item` 元素:
     <nav class="menu"> <a class="link menu__item" href=""></a> <a class="link menu__item" href=""></a> <a class="link menu__item" href=""></a> </nav>

    通过混合两个 BEM 实体,您现在可以从 `link` 块实现基本链接功能,并从 `menu` 块实现额外的 CSS 规则,并避免代码重复。

外部几何和定位:放弃抽象 HTML 包装器

混合用于相对于其他块定位块或定位块内的元素。 在 BEM 中,负责几何和定位的样式在父块中设置。 让我们看一个必须放在标题中的通用菜单块。 在布局中,块必须从父块缩进 20px。

这个任务有几个解决方案:

  1. 为菜单块编写带有缩进的样式:
     .menu { margin-left: 20px; }

    在这种情况下,“菜单”块不再通用。 如果必须将菜单放在页脚中,则必须编辑样式,因为缩进可能会有所不同。
  2. 创建菜单块修改器:
     <div> <ul class="menu menu_type_header"> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> </ul> </div>
     .menu_type_header { margin-left: 20px; } .menu_type_footer { margin-left: 30px; }

    在这种情况下,该项目将包括两种菜单,但事实并非如此。 菜单保持不变。
  3. 定义块的外部定位:将`menu`块嵌套在抽象包装器中(例如,`wrap`块)设置所有缩进:
     <div class="wrap"> <ul class="menu"> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> </ul> </div>

    为了避免创建修饰符和更改块样式以将块定位在页面上的诱惑,您需要了解一件事:

    父块的缩进不是嵌套块的特征。 这是父块的一个特性。 它必须知道嵌套块必须从边界缩进一定数量的像素。
  4. 使用混合。 有关嵌套块定位的信息包含在父块元素中。 然后将父块元素混合到嵌套块中。 在这种情况下,嵌套块没有指定任何缩进,并且可以在任何地方轻松重用。

让我们继续我们的例子:

 <div> <ul class="menu header__menu"> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> </ul> </div>

在这种情况下, menu块的外部几何形状和位置是通过header__menu元素设置的。 menu块没有指定任何缩进并且可以很容易地重复使用。

父块元素(在我们的例子中是header__menu )执行负责块外部定位的包装块的任务。

文件结构中的块

所有 BEM 项目都具有相似的文件结构。 熟悉的文件结构使开发人员可以更轻松地导航项目、在项目之间切换以及将块从一个项目移动到另一个项目。

每个块的实现都存储在单独的项目文件夹中。 每种技术(CSS、JavaScript、测试、模板、文档、图像)都在一个单独的文件中。

例如,如果使用 CSS 设置input块外观,则代码保存在input.css文件中。

 project common.blocks/ input/ input.css # The "input" block implementation with CSS input.js # The "input" block implementation with JavaScript

修饰符和元素的代码也存储在块的单独文件中。 这种方法允许您在构建中仅包含实现块所需的那些修饰符和元素。

 project common.blocks/ input/ input.css # The "input" block implementation with CSS input.js # The "input" block implementation with JavaScript input_theme_sun.css # The "input_theme_sun" modifier implementation input__clear.css # The "input__clear" element implementation with CSS input__clear.js # The "input__clear" element implementation with JavaScript

为了改进项目导航,将块修饰符与目录中的多个值结合起来。

任何 BEM 项目的文件结构都由重新定义级别组成(您可以在此处了解有关它们的更多信息)。 重新定义级别允许您:

  • 将项目划分为平台;
  • 轻松更新项目中包含的块库;
  • 使用通用块开发多个项目;
  • 在不影响项目逻辑的情况下改变设计主题;
  • 在现场项目中进行实验。

使用块并将所有块技术存储在同一个文件夹中,可以轻松地在项目之间移动块。 要将块的所有样式和行为与布局一起移动,只需将块文件夹复制到新项目即可。

方法论的非明显优势

并行开发的便利

在 BEM 中,任何布局都分为块。 由于块是独立的,它们可以由多个开发人员并行开发。

开发人员创建一个块作为可以在任何其他项目中重用的通用组件。

一个示例是 bem-components 块库,其中包含通用块,例如链接、按钮和输入字段。 从通用组件创建更复杂的块更容易。 例如,选择器或复选框。

在项目布局中使用块可以帮助您节省集成多个开发人员编写的代码的时间,保证组件名称的唯一性,并允许您在开发阶段测试块。

测试布局

测试整个页面的功能是有问题的,尤其是在连接到数据库的动态项目中。

在 BEM 中,每个块都被测试覆盖。 测试是一种块实现技术,如 Javascript 或 CSS。 块在开发阶段进行测试。 更容易检查一个块的正确性,然后从测试的块组装项目。 之后,您所要做的就是确保块包装器正常工作。

可定制的项目构建

为了方便开发,BEM 项目中的所有模块和技术都放在单独的文件夹和文件中。 要将源文件合并到一个文件中(例如,将所有 CSS 文件放在project.css中,将所有 JS 文件放在project.js中,等等),我们使用构建过程。

构建执行以下任务:

  • 组合分布在项目文件系统中的源文件;
  • 仅包括项目中必要的块、元素和修饰符(BEM 实体);
  • 遵循包含实体的顺序;
  • 在构建期间处理源文件代码(例如,将 LESS 代码编译为 CSS 代码)。

要在构建中仅包含必要的 BEM 实体,您需要创建页面上使用的块、元素和修饰符的列表。 此列表称为声明

由于 BEM 块是独立开发的,并放置在文件系统中的单独文件中,因此它们彼此不“了解”任何信息。 要基于其他块构建块,请指定依赖项。 有一种 BEM 技术对此负责: deps.js文件。 依赖文件让构建引擎知道项目中必须包含哪些附加块。

实际案例:BEM 不仅仅适用于 CSS

在前面的部分中,所有代码示例都是针对 CSS 的。 但是 BEM 允许您以与 CSS 中相同的声明方式修改块的行为及其在 HTML 中的表示。

如何在 BEM 中使用模板

在 HTML 中,每次块出现在页面上时都会重复块标记。 如果您手动创建 HTML 标记,然后需要修复错误或进行更改,您将需要修改块的每个实例的标记。 为了自动生成 HTML 代码并应用修复,BEM 使用模板; 块负责它们在 HTML 中的呈现方式。

模板允许您:

  • 减少用于项目调试的时间,因为模板更改会自动应用于所有项目块;
  • 修改区块布局;
  • 将具有当前布局的块移动到另一个项目。

BEM 使用具有两个引擎的 bem-xjst 模板引擎:

  • BEMHTML
    将页面的 BEMJSON 描述转换为 HTML。 模板在 .bemhtml.js 文件中描述。
  • 贝姆特里
    将数据转换为 BEMJSON。 模板在.bemtree.js文件中以 BEMJSON 格式描述。

如果没有为块编写模板,则模板引擎默认为块设置<div>标签。

比较块的声明和 HTML 输出:

宣言:

 { block: 'menu', content: [ { elem: 'item', content: { block: 'link'} }, { elem: 'item', elemMods: { current: true }, // Set the modifier for the menu item content: { block: 'link' } } ] }

HTML:

 <div class="menu"> <div class="menu__item"> <div class="link"></div> </div> <div class="menu__item menu__item_current"> <div class="link"></div> </div> </div>

要修改menu块布局,您需要为该块编写模板:

  1. 让我们更改menu块标签:
     block('menu')( tag()('menu') // Set the "menu" tag for the menu block )

    修改后的 HTML:
     <menu class="menu"> <!-- Replace the "div" tag with the "menu" tag for the "menu" block --> <div class="menu__item"> <div class="link"></div> </div> <div class="menu__item menu__item_current"> <div class="link"></div> </div> </menu>

    与 CSS 类似,模板适用于页面上的所有“菜单”块。
  2. 添加一个额外的元素 ( menu__inner ) 作为内部包装器并负责menu块中元素的布局。 最初menu__inner元素没有包含在声明中,所以我们必须在构建模板时添加它。

    BEM 模板是用 JavaScript 编写的,因此您也可以使用 JavaScript 向模板添加新元素:
     block('menu')( tag()('menu'), content()(function() { return { elem: 'inner', content: this.ctx.content }; }) )
     <menu class="menu"> <!-- Replace the "div" tag with the "menu" tag for the "menu" block --> <div class="menu__inner"> <div class="menu__item"> <div class="link"></div> </div> <div class="menu__item menu__item_current"> <div class="link"></div> </div> </div> </menu>
  3. 替换所有inneritem元素的标签:
     block('menu')( tag()('menu'), content()(function() { return { elem: 'inner', content: this.ctx.content } }), elem('inner')( tag()('ul') ), elem('item')( tag()('li') ) )
     <menu class="menu"> <ul class="menu__inner"> <li class="menu__item"> <div class="link"></div> </li> <li class="menu__item menu__item_current"> <div class="link"></div> </li> </ul> </menu>
  4. 为页面上的所有链接设置<a>标签:
     block('menu')( tag()('menu'), content()(function() { return { elem: 'inner', content: this.ctx.content } }), elem('inner')( tag()('ul') ), elem('item')( tag()('li') ) ); block('link')( tag()('a') );
     <menu class="menu"> <ul class="menu__inner"> <li class="menu__item"> <a class="link"></a> </li> <li class="menu__item menu__item_current"> <a class="link"></a> </li> </ul> </menu>
  5. 修改现有模板。 模板中规则的应用方式与 CSS 中相同:较低的规则覆盖较高的规则。 向模板添加新规则,并将链接标签从<a>更改为<span>
     block('link')( tag()('a') ); block('link')( tag()('span') );
     <menu class="menu"> <ul class="menu__inner"> <li class="menu__item"> <span class="link"></span> </li> <li class="menu__item menu__item_current"> <span class="link"></span> </li> </ul> </menu>

BEM 是一个可定制的系统

BEM 方法为您提供了在项目中创建系统的严格规则。 但同时可以自定义很多边界元规则。 BEM 方法允许您更改命名约定、选择最方便的文件结构或将您想要的任何技术添加到块中。

现在您可以调入系统并制作您自己的 BEM 超级英雄!

BEM 作为美国队长的标志
BEM 美国队长

如何从 BEM 中获得更多收益

要开始学习 BEM 原理,请访问我们的网站。 如果您有任何问题想向团队提问,请加入我们的 Telegram 频道或在我们的 BEM 论坛中进行讨论。