【问题标题】:How to structure BEM modifiers with nested elements in SASS如何在 SASS 中使用嵌套元素构造 BEM 修改器
【发布时间】: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 & { - 查看我的答案了解详情。希望对将来遇到此问题的人有用

标签: html css sass bem


【解决方案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 我认为这就是问题所要求的
        猜你喜欢
        • 2020-09-25
        • 2022-01-16
        • 1970-01-01
        • 2019-06-14
        • 2014-07-03
        • 2019-09-30
        • 1970-01-01
        • 2018-11-06
        • 2015-07-14
        相关资源
        最近更新 更多