如何在 SASS 中使用嵌套元素构造 BEM 修改器

Posted

技术标签:

【中文标题】如何在 SASS 中使用嵌套元素构造 BEM 修改器【英文标题】:How to structure BEM modifiers with nested elements in SASS 【发布时间】:2017-11-11 00:49:42 【问题描述】:

SASS + BEM 在大多数情况下几乎是天作之合,但我的一个常见难题是了解如何在使用 SASS 父选择器时在影响其子元素的元素上最好地定义 BEM 修饰符。

我在 SASS 中使用 BEM 样式语法定义了以下组件:

.card 
  background-color: #FFF;

  &__value 
    font-size: 2em;
    color: #000;
  

由于 SASS 的父选择器,这很有效。它使相关代码井井有条且自成体系。

但是当我需要添加一个使用父选择器改变子元素的修饰符时,这个想法很快就崩溃了:

.card 
  padding: 2em;

  &__value 
    font-size: 1.5em;
    color: #000;
  

  &--big 
    padding: 2.5em;

    &__value           // Is this going to work?
      font-size: 3em;
    
  

不。它会生成这个:

.card 
  padding: 2em;

.card__value 
  font-size: 1.5em;
  color: #000;

.card--big 
  padding: 2.5em;

.card--big__value   // Wrong
  font-size: 3em;

以某种方式获得这个选择器会更有意义:

.card--big .card__value 
  font-size: 3em;

这样做的原因是,您可以简单地将修饰符添加到***元素并使其影响任何或所有子元素。

我尝试了几种方法:

使用两个结构

.card 
  padding: 2em;

  &__value 
    font-size: 1.5em;
    color: #000;
  


.card--big 
  padding: 2.5em;

  &__value 
    font-size: 3em;
  

这很有效(尤其是在这个简化的演示中),但是在具有许多修饰符的更复杂的组件集合中,这可能是维护和保持无错误的潜在痛苦。此外,如果可能的话,最好继续使用 SASS 父选择器。

为元素使用变量

.card 
  $component: &;  // Set the variable here

  padding: 2em;

  &__value 
    font-size: 1.5em;
    color: #000;
  

  &--big 
    padding: 2.5em;

    #$component__value   // Use it here
      font-size: 3em;
    
  

这很好用。但是将元素定义为变量似乎有点愚蠢。也许这是做到这一点的唯一真正方法......我不确定。有没有更好的选择来构建它?

【问题讨论】:

好点!这是最干净的嵌套方式,而不是使用一百个 mixin。我认为您的问题是自我回答的。 可以用一个字符 &--big 变成 &--big & - 查看我的答案了解详情。希望对将来遇到此问题的人有用 【参考方案1】:

为什么不这样做呢?

.card 
  padding: 2em;

  &__value 
    font-size: 1.5em;
    color: #000;
  

  &--big 
    padding: 2.5em;
  

  &--big &__value   
    font-size: 3em;
  

【讨论】:

是的,这是可能的解决方案之一。不理想,因为您重复组件类名称,但还不错。 真的!我也喜欢你的变量选项,非常有创意!【参考方案2】:

您可以将修饰符拆分为不同的结构,但嵌套在 .card 选择器中,如下所示:

.card 
  padding: 2em;

  &__value 
    font-size: 1.5em;
    color: #000;
  

  &--big 
    padding: 2.5em;
  

  &--big &__value 
    padding: 2.5em;
  

这又会产生这个:

.card 
  padding: 2em;

.card__value 
  font-size: 1.5em;
  color: #000;

.card--big 
  padding: 2.5em;

.card--big .card__value 
  padding: 2.5em;

我认为这是一个几乎完美的方式,虽然它不是完美的嵌套 我希望这是一个帮助!

【讨论】:

【参考方案3】:

我刚刚找到了一个更好的方法来使用 sass 实现这一点,通过使用变量来存储父选择器的值,您可以在任何级别的嵌套中使用它!

例如,这里我将.card 选择器存储在$this 变量中,并像#$this 一样重用它

所以这段代码

.card 
  padding: 2em;

  &__value 
    font-size: 1.5em;
    color: #000;
  
  $this: &;

  &--big 
    padding: 2.5em;

    #$this__value 
      font-size: 3em;
    
  

将编译为

.card 
  padding: 2em;

.card__value 
  font-size: 1.5em;
  color: #000;

.card--big 
  padding: 2.5em;

.card--big .card__value 
  font-size: 3em;

这个答案的灵感来自css-tricks 上的这篇文章。感谢Sergey Kovalenko

【讨论】:

谢谢,但这正是我在问题中提出的建议。 我看你是对的,我在你刚才问的时候看到了你的问题,现在我看到了这篇文章,所以我才发布它【参考方案4】:

您可以在这里使用另一种模式。

这将: - 将实际的卡片修饰符与其元素的修饰符分开 - 将修改后的样式保留在相同元素的选择器中,因此您无需上下滚动代码即可查看正在修改的内容 - 将阻止更具体的规则出现在不太具体的规则之上,如果这是你的事

这是一个例子:

// scss
.card 
  $component: &;

  padding: 2em;

  &--big 
    padding: 2.5em;
  

  &__value 
    font-size: 1.5em;
    color: #000;

    #$component--big & 
      font-size: 3em;
    
  


/* css */
.card 
  padding: 2em;

.card--big 
  padding: 2.5em;

.card__value 
  font-size: 1.5em;
  color: #000;

.card--big .card__value 
  font-size: 3em;

【讨论】:

【参考方案5】:

您的解决方案看起来不错,但您也可以尝试@at-root。

【讨论】:

到底是什么?我不明白为什么@at-root 可以提供帮助。【参考方案6】:
.card 
  padding: 2em;

  &__value 
    font-size: 1.5em;
    color: #000;
  

  &--big 
    padding: 2.5em;

    &__value           // Is this going to work?
      font-size: 3em;
    
  

您可以通过以下方式达到您想要的结果:

.card 
  padding: 2em;

  &__value 
    font-size: 1.5em;
    color: #000;
  

  &--big 
    padding: 2.5em;

    .card 
       &__value           // this would work
          font-size: 3em;
       
    
  

【讨论】:

确实如此,但它远离了使用父选择器。尽可能多地使用它很好。【参考方案7】:

通过相同的问题,我构建了一个名为 Superbem 的库,它基本上是一组 SCSS 混合,可帮助您编写 BEM 声明方式。看看:

@include block(card) 
    padding: 2em;

    @include element(value) 
        font-size: 1.5em;
        color: #000;
    

    @include modifier(big) 
        padding: 2.5em;

        @include element(value) 
            font-size: 3em;
        
    

给你:

.card, .card--big 
    padding: 2em; 


.card__value 
    font-size: 1.5em;
    color: #000; 


.card--big 
    padding: 2.5em; 


.card--big .card__value 
    font-size: 3em; 

希望你会发现这很有用!

【讨论】:

【参考方案8】:

你可以通过添加一个字符来做到这一点,不需要变量或混合。

&--big 变为 &--big &

.card 
  padding: 2em;

  &__value 
    font-size: 1.5em;
    color: #000;
  

  &--big & 
    padding: 2.5em;

    &__value           // Is this going to work? (yes!)
      font-size: 3em;
    
  

【讨论】:

这不会导致.card--big .card__value 吗? @JakeWilson 我认为这就是问题所要求的

以上是关于如何在 SASS 中使用嵌套元素构造 BEM 修改器的主要内容,如果未能解决你的问题,请参考以下文章

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

BEM规范

带 SASS 和 :hover 的 BEM

html Sass&BEM:灵活的组件定义#sass

css BEM SASS(3.3)

scss BEM-SASS