BEM修饰符:多类名 VS Sass @extend

发布于 大漠

本文由大漠根据Ben Smithett的《BEM modifiers: multiple classes vs @extend》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明原作者相关信息http://bensmithett.com/bem-modifiers-multiple-classes-vs-extend/

——作者:Ben Smithett

——译者:大漠

多类名的运用是好的,但每个元素往往局限于单个修饰符类名和单个状态类名或自定义的data属性中。如下所示:

<div class="comment comment--admin is-disabled">

或者:

<div class="comment comment--admin" data-state="disabled">

有一阵子我都主张修饰符是独立的,像这样:

.comment{
  color: $black;
}
.comment--admin{
  @extend .comment;
  background-color: $green;
}
<div class="comment">...</div>
<div class="comment--admin">...</div>

我想我错了,这也是我为什么现在更喜欢在某个元素上使用多个类名:

不按规范修改模块

comment--admin类名实际上有点作做。大多数模块不需要“完全相同,但略有不同”。常常使用这种方式来替换:

// 基本模块
.comment{
  color: $black;

  // 限定作用域状态类名和伪元素
  &:hover,
  &:focus{
    color: $blue;
  } 
  &.is-disabled{
    color: $grey;
  }
  // & maybe some modifications based on
  // Modernizr or Metaquery classes on <html>
  .no-svg &{
    background-image: url(lame.png);
  }
  .breakpoint-desktop &{
    font-size: 20px;
  }  
}    

当你需要对模块进行修改时,使用@extend来扩展选择器为的就是避免在html结构中增加类名,这真的并不是重点。而只更新需要更新的属性类名,这样真的要好些:

.comment{
  background-color: $white;
  color: $black;
}
.comment--admin{
  background-color: $green;
}  
<div class="comment comment--admin">

额外的类只是用来修改你需要修改的属性,而其他的仍然保持继承默认版本中默认的属性。

多类名意味着源码顺序的重要性

这可能是最主要的原因,直到现在我一直都在避免多个类在一起使用:

.comment{
  color: $black;
}
.comment--admin{
  color: $green;
}
.comment--important{
  color: $yellow;
  font-weight: bold;
}  
<div class="comment comment--admin comment--important">

如果修饰符类名修改了相同属性,那么最后一个出现的会覆盖前面的属性。目测之下,这样一来模块不能在任何地方重用。

幸运的是这个问题很容易解决,在元素上使用不只一个的修饰符类名。

创建一个新的修饰符类名,将他们组合在一起,事情真的变得非常方便:

.comment{
  color: $black;
}
.comment--admin{
  color: $green;
}
.comment--important{
  color: $yellow;
  font-weight: bold;
}
.comment--admin-important{
  color: $green;
  font-weight: bold;
}  
<div class="comment comment--admin-important">

模块局部状态类名用来确保其特殊性

在元素上你除了可以设置一个修饰符类名之外,你还可添加一个状态类名:

<div class="comment comment--admin is-disabled">

状态类名总是用来覆盖模块基本样式或修饰符中的样式。

.comment}
  color: $black;

  &.is-disabled{
    color: $grey;
  }
}    

你可以肯定他和模块基本样式和修饰符样式相比总是有自己的特殊性。

和修饰符类名一样,当你不知道用什么状态类名来替代的时候,你也可以同时定义多个状态类名。

你可能想用自定义的data属性来指定元素的状态,而不是使用一个类名。使用JS来更新一个data属性的值比添加或删除特定的类名要简单的多。也非常鼓励他们分散出来,而不是一味的组合在一起。

<div class="comment comment--admin" data-state="disabled">
.comment{
  color: $black;

  &[data-state=disabled]{
    color: $grey;
  }
  &[data-state=loading]{
    background: url(spinner.gif);
  }
}    

按钮?

<button>常常被拿来做为修饰符使用的一个典型案例。出于某种原因,希望按钮是可以无限制实现定制。

<button class="btn btn--warning btn--large btn--round btn--icon">

以我的经验来看,按钮在这方面的确是一个很好的案例,至少其他模块不需要这么多的变化。

虽然在一些特殊情况这定破坏一些规则就行了。甚至可以说它是在试图在不同情况下一刀切。

如此一来,可能只需要使用多个修饰符类名,并且让团队成员知道他们的特殊性。

或者可以使用不同的命名来约定,使用修饰符变得特别的明显。这也是我一直在尝试做的一件事:

<button class="btn -color-red -size-large -shape-round">
.btn{
  &.-color-red{
    color: $red;
  }
  &.-color-blue{
    color: $blue;
  }
  &.-size-med{
    font-size: 1em;
  }
  &.-size-large{
    font-size: 2em;
  }
  // etc etc
}  

在源码顺序中,这也存在一定的风险,但一些智能的命名配合&一起使用就可以避免一些戏剧性的事情发生。

多类名胜出

在某个元素上使用多个类名与使用一个类名相比,肯定带有一定的风险。但如果你一直坚持"一个修改符类名,一个状态类名"原则,这些风险是可以避免的。

扩展阅读

译者手语:整个翻译依照原文线路进行,并在翻译过程略加了个人对技术的理解。如果翻译有不对之处,还烦请同行朋友指点。谢谢!

如需转载烦请注明出处:

英文原文:http://bensmithett.com/bem-modifiers-multiple-classes-vs-extend/

中文译文:https://www.fedev.cn/preprocessor/bem-modifiers-multiple-classes-vs-extend.html

Air Foamposite One