假设我有一个带样式的复选框(想想材料设计,有一点可以实现所需的复选框样式)。哪个块负责修改父依赖子块?
示例组件 - 复选框
所以我有以下内容:
<div class="Checkbox">
<label class="Checkbox__label">
<input class="Checkbox__input" type="checkbox" checked=true />
<span class="Checkbox__icon glyphicon glyphicon-ok"></span>
<span class="Checkbox__text">{label}</span>
</label>
</div>
我为块中的每个元素设置基础复选框的样式。在应用程序的上下文中,复选框块可以存在于许多其他块中(具有自己的BEM结构)。
其他区块的示例
当在“紧凑面板”中说出时,该复选框的外观略有不同:
<div class="Panel Panel--compact">
<p>Disclaimer.. [text]</p>
<Checkbox label="I Agree" />
</div>
选项一 - 家长“知道”关于孩子
所以.. Compact Panel
应该“意识到”各种儿童阻拦,并对其进行设计,所以:
// Checkbox.scss
.Checkbox {
margin: 15px;
// .. other
}
// Panel.scss
.Panel {
&.Panel--compact {
margin: 0;
padding: 2px;
}
&.Panel--compact .Checkbox {
margin: 0;
padding: 1px;
}
}
选项二 - 儿童“知道”父母
或者,面板没有意识,复选框检查父范围。
// Checkbox.scss
.Checkbox {
margin: 15px;
padding: 15px;
// .. other
}
.Panel.Panel--compact .Checkbox {
margin: 0;
padding: 1px;
}
// Panel.scss
.Panel {
&.Panel--compact {
margin: 0;
padding: 2px;
}
}
选项三 - ?
也许还有其他选择。
答案 0 :(得分:4)
通常使用BEM,如果看起来不同,则 不同。
一般
使用BEM处理上下文和状态有许多不同的选择。每个都有不同的优点和缺点,所以你使用它将在很大程度上取决于你的用例。
我提到的第一个选项是使用后代选择器。您已经确定了这个选择,并且遇到了通常的问题&#34;代码属于哪里?&#34;
对于以下示例,我将依赖LESS语法,这只是为了让我更容易在代码中展示关系。
如果您要使用后代选择器,我建议将代码与子块分组。
<子> widget.less 子>.widget {
&__container {
...
}
...
}
<子> checkbox.less 子>
.checkbox {
&__label {
...
}
...
// using inversion to override checkbox styles in a widget
// this will render to `.widget .checkbox` instead of
// `.checkbox .widget` due to the `&` placement
.widget & {
}
}
我建议将样式与内部块相关联的原因是样式会影响复选框,并且级联顺序很重要。
如果样式与父项相关联,则相对于子样式重新排序父样式可能会对样式的呈现方式产生负面影响。
考虑这个包含顺序:
<子> site.less 子>@import 'widget';
@import 'checkbox';
如果样式是小部件的一部分,它们可以被checkbox.less
中具有相同特异性的选择器覆盖。
我建议使用修饰符进行状态。我通常不会将位置或背景视为&#34; state&#34;,因此修饰符可能不合适。另外,同一元素上的多个修饰符可能难以推理,因此难以定型。
假设您未在checkbox
块上使用修饰符,则可以更简单地为面板中使用的修改器添加修饰符。
.checkbox {
&__label {
...defaults...
}
...defaults...
&--alt {
&__label {
...overrides...
}
...overrides...
}
}
当然,这需要针对在面板中使用的特定情况更新标记,但随后它还会打开您使用其他地方相同样式的复选框。
我要重申我的第一点:如果他们看起来不同,他们 就不一样了。
这并不意味着您必须从复选框开始。 BEM允许面向对象的样式。想出一个新名称,然后扩展 *复选框:
<子> checkbox.less 子>.checkbox {
&__label {
...
}
...
}
<子>复选框-2.less 子>
@import (reference) 'checkbox';
.checkbox-2 {
.checkbox;
&__label {
...overrides...
}
...overrides...
}
*我很少使用mixin,因为它通常比使用该语言的:extend
功能更适合扩展和覆盖样式。您可以随意使用:extend
功能,只需注意选择器顺序即可。
有时我会遇到我想要使用后代选择器或修饰符的情况,因为我需要在容器中碰撞块以进行定位。
在这些情况下,我经常发现容器本身应该改变。当我需要将孩子更新为不同时,我通常可以说它是容器:
重构伴随着其他挑战,但是我经常最终使用容器div来规范化包含其他块的块的插入区域; YMMV。
您(合理地)可以更新标记吗?
是:如果您可以轻松更新标记以使用不同的类,我建议将checkbox
块扩展为新块。命名事情很难,所以一定要记录哪个是某个地方。
NO:如果您无法轻松更新课程,使用修饰符也不是一个很好的选择。我建议跳过那个,然后回到好的地方。 后代选择器。在BEM中,您确实想要避免后代选择器,但有时它们是适合该工作的正确工具。
答案 1 :(得分:2)
根据this documentation,在BEM中应避免使用嵌套选择器,但“适用于更改元素,具体取决于块的状态或其指定的主题“。这意味着您可以使用块的修饰符来设置其元素的样式,但我找不到使用块的修饰符来设置其子块的样式。
我认为最好的方法是为.Pannel
和.Checkbox
块添加修饰符,例如:.Panel--compact
和.Checkbox--context-compact
。这样你就不会在它们之间创建一个依赖关系,这是一个BEM原则。
如果以某种方式无法向.Checkbox
添加修饰符,具体取决于它的上下文,我认为最接近的选项是第二个选项,其中子项的行为取决于其父项的状态。
答案 2 :(得分:0)
我很惊讶为什么接受的答案没有提到BEM“混合”。 在这些情况下,也就是说,当一个块在另一个块中使用时应更改样式时,the official BEM documentation recommends使用一个块和同一DOM节点上的元素类。
因此,在您的情况下,这就是标记:
<div class="Panel Panel--compact">
<p>Disclaimer.. [text]</p>
<div class="Checkbox Panel__checkbox" /> <!-- Here is the change -->
</div>
这就是CSS / SCSS:
// Checkbox.scss
.Checkbox {
margin: 15px;
padding: 15px;
// .. other
}
// Panel.scss
.Panel {
&__checkbox {
margin: 0;
padding: 2px;
}
}
真的很简单。其他答案不必要地使这一问题变得过于复杂,我不知道为什么,BEM文档对这个问题有明确的答案。您还可以在网上找到许多文章,这些文章解释了我刚刚描述的相同技术。
答案 3 :(得分:-1)
我最近开始了一个反应项目,我想分享我在造型反应组件方面的经验。
反应组件中的层叠样式确实令人困惑。所以首先要尝试为每个元素编写类。如果需要,可以使用定义组件的主类进行换行。
.panel {
.checkbox {
}
}
我使用css-modules。这太棒了。此工具可以创建唯一的类,因此您无需担心在其他组件中复制相同的名称。您可以从他们的git页面了解更多信息,并且在线有很多文章。
如果你正在使用sass并且需要使用变量,你可以在另一个文件夹中定义一个单独的sass文件(比如说../assets/variables.scss
),在组件scss文件中你可以导入它并使用所有变量。 mixins和函数也一样。
在您的情况下,不要担心子关系和父关系,为您需要设置样式的所有元素编写单个类。有时您可能需要使用父级来定位孩子。