关于 BEM 最好的介绍来自 Harry Roberts
BEM——代表块 (block)、元素 (element)、修饰符 (modifier)——是一种由 Yandex 公司开发的前端命名方法。它是一种为 CSS 类命名以提高透明度和可读性的智能方法。它们更加严格和信息丰富,这使得 BEM 命名约定非常适合大型项目的开发团队,这些项目可能持续一段时间。
从 Sass 3.3 开始,我们可以这样写
.block {
/* CSS declarations for `.block` */
&__element {
/* CSS declarations for `.block__element` */
}
&--modifier {
/* CSS declarations for `.block--modifier` */
&__element {
/* CSS declarations for `.block--modifier__element` */
}
}
}
只要 CSS 规则简短且基本选择器简单,可读性就还可以。但是,当事情变得更加复杂时,这种语法会使我们难以理解发生了什么。因此,我们可能会倾向于为 BEM 语法构建两个包装 mixin
/// Block Element
/// @access public
/// @param {String} $element - Element's name
@mixin element($element) {
&__#{$element} {
@content;
}
}
/// Block Modifier
/// @access public
/// @param {String} $modifier - Modifier's name
@mixin modifier($modifier) {
&--#{$modifier} {
@content;
}
}
使用我们全新的 mixin 重写之前的示例
.block {
/* CSS declarations for `.block` */
@include element('element') {
/* CSS declarations for `.block__element` */
}
@include modifier('modifier') {
/* CSS declarations for `.block--modifier` */
@include element('element') {
/* CSS declarations for `.block--modifier__element` */
}
}
}
请注意,字符串周围的引号是可选的,我们仅为了提高可读性而添加它们。
现在,如果您觉得 element
和 modifier
太长,可以像这样创建两个较短的别名
/// @alias element
@mixin e($element) {
@include element($element) {
@content;
}
}
/// @alias modifier
@mixin m($modifier) {
@include modifier($modifier) {
@content;
}
}
使用别名
.block {
/* CSS declarations for `.block` */
@include e('element') {
/* CSS declarations for `.block__element` */
}
@include m('modifier') {
/* CSS declarations for `.block--modifier` */
@include e('element') {
/* CSS declarations for `.block--modifier__element` */
}
}
}
第二个 &__element 不会产生 .block–modifier__element 吗?
已修复,非常感谢!
错误。教程。第一个回复是正确的。修饰符始终位于最后位置。
并且 mixin 的使用带来了不必要的复杂性。
我不明白为什么要过度复杂化 Sass 代码。这会让新手望而却步。默认方式更短,更容易理解……
.block {
color: black;
&__element { border: 1px solid; }
}
&__element
对于你来说可能更容易理解,但对于你所说的新手来说,这种语法可能不友好。让人们选择他们自己的工具。完全同意你的观点,引入 mixin 会降低可读性
100% 同意 luis 的观点。这不是在解决问题,实际上是在使事情复杂化。“新手”学习这个 mixin 的时间,他们本可以弄清楚
&__element
是做什么的。我的意思是他们仍然需要在 HTML 中添加类,对吧?!我不同意 luis 的观点。我确实认为新手应该学习如何在使用这些 mixin 之前使用 &__,就像他们应该在学习 SASS/LESS 之前学习 CSS 一样。
我认为这些 mixin 在你不再是新手并且想要使你的代码更具语义并更有意义时会派上用场——并使你的大脑能够更快地用简单的英语理解每一行代码的含义。
此外,在使用 SASS 语法时,这些 mixin 使用起来非常简短快捷
对我来说,这似乎比为“新手”声明一个与号更复杂。如何期望一个“新手”知道如何编写 mixin 和包含,而不是简单地弄清楚他们可以传递一个与号来嵌套选择器?
@include m('modifier') { ... }
仍然是比简单地写出一个简单声明更昂贵(且不必要)的填充。如果说有什么的话,这鼓励人们或“新手”使用代价高昂的操作来开始嵌套所有内容。这与本文中提到的内容几乎相反 这里。可能会忽略这一点实际上“有用”,但我愿意接受意见!:-)
干杯。
……而且,现在一个更难以搜索的代码库,这又让我回到了嵌套选择器时注释的有用性——再次与上面文章的引用相反。嗯。我需要说服!哈哈。
大家好,你们有没有注意到他们现在使用单个下划线“_”而不是双破折号“–”作为修饰符?
http://en.bem.info/method/definitions/
实际上,即使我发现它有点难以阅读,我也不会反对它,但如果你们中的任何人知道他们为什么做出这个选择,我很乐意知道。
我尝试这样做,但我遇到了这个错误
在“ ... element(input)”之后出现无效的 CSS:预期为“}”,但为“,”
我使用这个来解决我的问题。
mixin 可以接受多个参数来设置多个元素的样式吗?
我自己的 SCSS 结构方式,到目前为止,我与之合作的其他人发现它易于理解/扩展/维护……但我一直在关注 OOCSS、SMACSS、BEM 等内容。
在我看来,这种方法在以下情况下会失效……
(假设使用 Jade 进行标记)
假设
--disabled
类由ng-class
应用。如果我想让我的图标/文本根据按钮是否为--disabled
具有不同的属性,我需要执行以下操作……这似乎更像是一种烦恼,或者我是否在考虑错误的用例?
好问题。我通常使用属性选择器来解决这个问题,如下所示
不幸的是,这对于具有多个类的 HTML(如
.btn.primary
)不起作用,但我通常也会避免这种情况,使用一个类来表示事物,并使用 Sass 来确定表示层。遵循 BEM 约定,您无需在元素中指定块修饰符。因此
.button--disabled__icon
不被视为有效的 BEM 代码。相反,您的嵌套应该如下所示
为了使其正常工作,编译后的 CSS 结构将为
可以通过更新“不必要”的 mixin 并使其了解此用例来实现此输出。现在 mixin 实际上变得有用了。
使用 Sass 3.4,可以在
&
选择器上执行字符串函数。这非常令人兴奋,因为在
modifier()
和element
mixin 中,我们将能够1. 创建一个函数来检查父选择器是否已具有修饰符
2. 据此计算类名
详细说明,如果我们有这种类型的输入
element('icon')
mixin 将检查父选择器 (&) 是否已包含修饰符,并输出.block--modifier .block__element
,否则仅输出block__element
。我喜欢使用这些 mixin 生成 BEM 代码,但是
我该如何删除最后一个链接的
:after
?我做不到
BEM 方法背后的理念是将任何逻辑分解成小块,以便所有内容都变得更容易维护。我假设您代码中的“面包屑”是一个块,而项目和链接是元素。
确实,将一个元素嵌套在另一个元素内部不应该起作用(因为它违反了最基本的 BEM 规则)。但是您可以通过将项目变成一个块并从中构建一个块-元素-修饰符对象来使其工作。
因此,您将保留当前结构直至项目,然后在内部创建一个面包屑项目块,在其中定义高级链接逻辑
然后在 HTML 中,您可以使用这个新的 BEM 块来补充初始元素的逻辑
这有什么帮助?您现在已将逻辑分离到一个较小的 BEM 模块中,并拆分了职责。
项目元素
.breadcrumb__item
处理浮动,项目块.breadcrumb-item
处理链接和分隔符逻辑。如果您要向链接添加更多复杂性,例如图标或突出显示的修饰符,则只需更改此小型结构即可轻松实现。
我不认为
会起作用 -
e
混合器将尝试在其__link
选择器之上添加&:not(:last-child)
,这将导致类似这样的结果参见此 gist。除非我的
e
混合器不正确。实际上,我刚刚找到了一个解决方法 - 请参阅此 gist。关键是在
e
混合器上获取&
父选择器并扫描其中的伪选择器。如果存在,则将其切出。Danny 说得对,元素混合器应该比示例中提供的更复杂一些。仅仅检查选择器是否包含伪选择器是不够的,还需要考虑父级是否包含修饰符,以生成诸如
.block--modifier .element
之类的类,而不是.block--modifier__element
- 这不是有效的 BEM。你的 gist 应该可以正常工作。
我正在使用一组自定义混合器来涵盖更多用例,也许我可以写一篇简短的介绍并在此处发布链接,如果你认为它可能会有所帮助。
说得对!是的,我想看看你提出了什么方法来从父选择器中获取块/元素。我在一个看起来很有前途的库上打开了此问题。很高兴看到一个社区驱动的独立的 BEM 相关混合器库。
这是一篇博文,描述了一些更多用例和一组高级混合器,这些混合器有助于创建模块化且可维护的 BEM 结构。
https://m.alphasights.com/how-we-use-bem-to-modularise-our-css-82a0c39463b0#.o4tc7cevq
sderhbr rfvjui o
我仍然认为以开头为准(通配符)选择器不适用于嵌套的 & 符号(是的,我确实理解为什么这不起作用的逻辑,只是说说)。这将消除对双块选择器的需求。因此,与其使用
<div class="tile tile--disabled">
,不如只写<div class="tile--disabled">
,同时仍然能够在同一层级嵌套块中设置 tile 和禁用版本的样式。这将导致在 scss 中失去一层特异性(这可能非常有用)这确实是一个有趣的想法,你可以创建一个混合器,它可以接收通配符匹配类名并返回通配符 + 修饰符(还没有仔细考虑,但肯定可以做到)。
如果你真的讨厌标准的 BEM 约定,你还可以做另一件事,即在占位符中放置块属性,然后在所有修饰符上扩展这些属性。
它可能看起来像这样
这是在不重复生成的 CSS 属性的情况下执行此操作的一种方法。
但是修饰符的全部意义在于扩展元素或块的样式。我发现调用
class="
非常有用block__title
block__title--highlighted
block__title--with-icon
但最终这只是一个约定问题。
非常好。你的方法启发我去解决我一直以来在 Sass + BEM 中遇到的可读性问题:组合多个修饰符。
我扩展了你的混合器以接受多个参数
这使得像这样的 Sass 代码…
…生成以下 CSS
如果你感兴趣,自从这篇文章发布以来,我扩展了混合器想法。
https://github.com/alphasights/paint/blob/develop/styles/tools/_bem.scss
还有一个测试展示了一些可能的用例
https://github.com/alphasights/paint/blob/develop/test/tools/_bem.scss
我个人到目前为止还没有找到组合修饰符的充分理由,例如在你的情况下,我只会将修饰符命名为
warning-inverted
,但这绝对看起来像一个很好的解决方案。如果你觉得它有用,请告诉我 :)
较长的类名不会膨胀 HTML 标记吗?