BEM 块、命名和嵌套

Posted

技术标签:

【中文标题】BEM 块、命名和嵌套【英文标题】:BEM block, naming & nesting 【发布时间】:2014-04-29 06:12:01 【问题描述】:

我正在尝试围绕 BEM 命名约定。我被困在这一点上。我可能会误解一些东西,让我们看看。

我有一个侧边栏导航和一个内容导航。

我的侧边栏导航看起来像这样

<div class="sidebar">
    <ul class="sidebar__nav">
        <li class="nav__item"><a href="#" class="nav__link">LINK</a></li>
        <li class="nav__item"><a href="#" class="nav__link">LINK</a></li>
    </ul>
</div>

我的内容导航看起来像这样

<div class="content">
    <ul class="content__nav">
        <li class="nav__item"><a href="#" class="nav__link">LINK</a></li>
        <li class="nav__item"><a href="#" class="nav__link">LINK</a></li>
    </ul>
</div>

现在,如果我设置 .nav__item 的样式,我会遇到问题,它们出现在我的两个导航中并且不应该具有相同的样式。我应该在这里做一些嵌套,还是我将我的块和元素命名错误?

CSS 中的嵌套示例:

.content__nav .nav__item  background: Red; 

或者我应该这样命名:

<li class="content__nav__item"><a href="#" class="content__nav__link">LINK</a></li>

你能帮忙吗?

【问题讨论】:

【参考方案1】:

关于如何编写 BEM 类有许多变体,因此请注意它们是多个相互竞争的标准。它最初是一套松散的指导方针。自发布此答案以来,Yandex has significantly overhauled their official standard(这是一个相当大的改进)。我使用的 BEM 版本很大程度上来自 an article by Nicolas Gallagher。

此时我使用"Atomic OOBEMITLESS",这实际上只是一种表示类是模块化和命名空间的方式,选择器的特异性较低,并且可以使用允许缩放 CSS 的类来切换状态,在CSS 预处理器,使代码更加简洁和富有表现力。

话虽如此,我将使用以下 BEM 标准:

连字符的类名作为块:foo-bar 块名称后跟__,后跟元素的连字符类名称:foo-bar__fizz-buzz 块或元素名称后跟--,后跟带连字符的修饰符类名称:foo-bar--bazfoo-bar--baz__fizz-buzzfoo-bar__fizz-buzz--qux

BEM 短格式:block-name__element-name--modifier-name


您的示例中有三个不同的块:

    sidebar,它有一个sidebar__nav 元素 content,它有一个content__nav 元素 nav,具有nav__itemnav__link 元素

sidebarcontent 块似乎是同一块的变体,可以表示为 .region.region--sidebar.region.region--content

nav 块隐含在 ul 元素上,您应该使其显式:

<ul class="nav"><!-- could be content__nav or sidebar__nav as well if you choose -->
    <li class="nav__item"><a href="#" class="nav__link">LINK</a></li>
    <li class="nav__item"><a href="#" class="nav__link">LINK</a></li>
</ul>

一旦您指定 ul 元素是 nav 块,就可以修改 nav 块:

<ul class="nav nav--content">
    <li class="nav__item nav--content__item"><a href="#" class="nav__link nav--content__link">LINK</a></li>
    <li class="nav__item nav--content__item"><a href="#" class="nav__link nav--content__link">LINK</a></li>
</ul>

设置完 CSS 类后,all nav__item 元素的样式很简单:

.nav__item 
    ...styles here...

为内容nav__item 元素覆盖这些样式是:

.nav--content__item 
    ...styles here...

【讨论】:

好吧,这更有意义!非常感谢您的解释。 @zzzzBov 好的!好的...在哪里...? @CyrilCHAPON,我不明白你在问什么。 @zzzzBov “它已经被更加严格地形式化了” => 在哪里? =) @CyrilCHAPON,哦,那是指已被删除的评论,该评论链接到我已包含在我更新的答案 (en.bem.info) 中的 BEM 网站。我将删除“这篇文章早于...”的评论,因为从那以后我所做的更新已经不再相关。【参考方案2】:

你应该看看BEM's FAQ。

另一个元素中的元素的类名是什么? .block__elem1__elem2?

如果我的块结构复杂且其元素是嵌套的,我该怎么办?像 block__elem1__elem2__elem3 这样的 CSS 类看起来很吓人。 根据边界元法,块结构应该是扁平的;您不需要反映块的嵌套 DOM 结构。因此,这种情况下的类名将是:

.block
.block__elem1
.block__elem2
.block__elem3

而块的 DOM 表示可能是嵌套的:

<div class='block'>
    <div class='block__elem1'>
        <div class='block__elem2'>
            <div class='block__elem3'></div>
        </div>
    </div>
</div>

除了类看起来更好之外,它使元素仅依赖于块。因此,在对界面进行更改时,您可以轻松地将它们移动到整个块中。块 DOM 结构的变化不需要对 CSS 代码进行相应的更改。

<div class='block'>
    <div class='block__elem1'>
        <div class='block__elem2'></div>
    </div>
    <div class='block__elem3'></div>
</div>

【讨论】:

【参考方案3】:

考虑 _key_value 对修饰符的想法(块或元素与修饰符名称用一个下划线分隔,其值与另一个下划线分隔)。

区分修饰符是有意义的(例如,nav_type_contentnav_type_sidebar 都是关于 nav 出现在页面上的位置,但修饰符设置主题、大小或使链接通过 ajax 工作是不同的)和以便了解哪些修饰符不能在一个 DOM 节点上一起使用。

javascript 中使用 key: value 对也更方便。

并且有相当多的现成组件和工具使用这种约定:https://github.com/bem/

【讨论】:

以上是关于BEM 块、命名和嵌套的主要内容,如果未能解决你的问题,请参考以下文章

命名 BEM 子块 [重复]

如何使用 BEM 正确设置元素的范围?

BEM---前端css命名规范

吐血整理的前端代码规范系列 -- css规范

我使用的Bem的习惯

BEM规范