SMACSS和BEM:如何将模块定位在模块内?

Gil*_*man 14 css bem smacss

注意:我使用在BEM中称为的单词Module.同样使用修改后的BEM命名约定,请在答案中使用.BLOCK__ELEMENT--MODIFIER


假设我有一个.btn看起来像这样的模块:

.btn {
  background: red;
  text-align: center;
  font-family: Arial;

  i {
    width:15px;
    height:15px;
  }
}
Run Code Online (Sandbox Code Playgroud)

我需要创建.popup-dialog一个.btn内部的模块:

.popup-dialog {
  ...
  .btn {
    position: absolute;
    top: 10px;
    right: 10px;
  }
}
Run Code Online (Sandbox Code Playgroud)

在SMACSS和BEM中,您应该如何处理模块内部的模块?


在您的回答中,请确定正确的解决方案,并分析以下方法:(请注意,下面的所有示例都是基于或修改上述CSS)


方法1

[覆盖.btn里面的原始类.popup-dialog]

CSS:

.popup-dialog {
  ...
  .btn {  // override the original .btn class
    position: absolute;
    top: 10px;
    right: 10px;
  }
}
Run Code Online (Sandbox Code Playgroud)

加价:

<div class="popup-dialog">
  ...
  <button class="btn"><i class="close-ico"></i> close</btn>
</div>
Run Code Online (Sandbox Code Playgroud)

方法2

[在里面添加一个子类.popup-dialog]

CSS:

.popup-dialog {
  ...
  .popup-dialog__btn {
    position: absolute;
    top: 10px;
    right: 10px;
  }
}
Run Code Online (Sandbox Code Playgroud)

加价:

<div class="popup-dialog">
  ...
  <button class="btn popup-dialog__btn"><i class="close-ico"></i> close</btn>
</div>
Run Code Online (Sandbox Code Playgroud)

方法3

[ .btn带修饰符的子类]

CSS:

.btn--dialog-close {
  position: absolute;
  top: 10px;
  right: 10px;
}
Run Code Online (Sandbox Code Playgroud)

加价:

<div class="popup-dialog">
  ...
  <button class="btn btn--dialog-close"><i class="close-ico"></i> close</btn>
</div>
Run Code Online (Sandbox Code Playgroud)

方法4

[ .btn布局类的子类]

CSS:

.l-dialog-btn {       // layout
  position: absolute;
  top: 10px;
  right: 10px;
}
Run Code Online (Sandbox Code Playgroud)

加价:

<div class="popup-dialog">
  ...
  <button class="btn l-dialog-btn"><i class="close-ico"></i> close</btn>
</div>
Run Code Online (Sandbox Code Playgroud)

小智 17

在我最近的一个大型项目中努力解决这个问题,我赞赏你把这个问题引起了人们对SO的关注.

我担心这个问题没有一个"正确"的解决方案,而且会有点基于意见.但是,我会尽量做到客观,并就你对我的团队有用的四种方法以及没有给我的团队的方法提供一些见解.

另外我假设以下内容:

  • 您熟悉SMACCS方法(您阅读本书并在至少一个项目中实现它).
  • 您只对CSS类名使用(修改的)BEM命名约定,而不是BEM方法开发堆栈的其余部分.

方法1

显然是最糟糕的方法,有几个缺陷:

  • 它创造之间的紧密耦合.popup-dialog,并.btn通过使用基于上下文的选择.
  • 您将来可能会遇到特殊性问题,假设您将来会添加其他.btn元素.popup-dialog.

如果以某种方式你需要使用不变的类名,我建议至少通过使用直接子选择器来降低适用性的深度.

CSS:

.popup-dialog {...}

.popup-dialog > .btn {
  position: absolute;
  top: 10px;
  right: 10px;
}
Run Code Online (Sandbox Code Playgroud)

方法2

这实际上非常接近我们的解决方案.我们在项目中设置了以下规则,并证明它是健壮的:"模块不能有外部布局,但可以布局其子模块".这很大程度上受到SUITCSS框架的@necolas惯例的启发.注意:我们使用的是概念,而不是语法.

https://github.com/suitcss/suit/blob/master/doc/components.md#styling-dependencies

我们在这里选择了第二个选项,并将子模块包装在其他容器元素中.是的,它创建了更多标记,但是当我们无法控制HTML(嵌入来自其他网站等)时,我们仍可以使用第三方内容来应用布局.

CSS:

.popup-dialog {...}

.popup-dialog__wrap-btn {
  position: absolute;
  top: 10px;
  right: 10px;
}
Run Code Online (Sandbox Code Playgroud)

HTML:

<div class="popup-dialog">
  ...
  <div class="popup-dialog__wrap-btn">
    <button class="btn"><i class="close-ico"></i> close</button>
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)

方法3

这可能看起来很干净(扩展而不是覆盖),但事实并非如此.它将布局与模块样式混合在一起..btn--dialog-close如果您有另一个模块需要为关闭按钮设置不同的布局,那么在将来开启布局样式将没有用处.

方法4

这与方法3基本相同,但语法不同.布局类必须不知道它所布置的内容.另外,我不是热衷于l-prefix书中提出的语法.根据我的经验,它会产生更多的混乱而不是它的帮助.我们的团队完全放弃了它,我们只是把所有东西视为模块.但是如果我需要坚持下去,我会尝试从模块中完全抽象出布局,这样你就有了一些有用且可重复使用的东西.

CSS:

.l-pane {
  position: relative;
  ...
}

.l-pane__item {
  position: absolute;
}

.l-pane__item--top-right {
  top: 10px;
  right: 10px;
}

.popup-dialog { // dialog skin
  ...
}

.btn { // button skin
  ...
}
Run Code Online (Sandbox Code Playgroud)

HTML:

<div class="popup-dialog l-pane">
  <div class="l-pane__item l-pane__item--top-right">
    <button class="btn"><i class="close-ico"></i> close</button>
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)

我不会因为这种方法而对任何人提出过错,但根据我的经验,并非所有布局都可以以合理的方式进行抽象,并且必须单独设置.这也使其他开发人员更难理解.我从这个假设中排除了网格布局,它们很容易掌握并且非常有用.

你有它.出于上述原因,我建议尝试修改方法2.

希望能帮到你.