以下是来自客座博主 Joe Richardson、Robin Rendle 和 CSS-Tricks 团队的合作文章。Joe 想要写一篇关于 BEM 的文章,我们很喜欢,而且几乎每个人都有关于 BEM 的想法和意见,所以我们觉得我们可以一起合作。
块(Block)、元素(Element)、修饰符(Modifier) 方法论(通常称为 BEM)是 HTML 和 CSS 中类名的流行命名约定。它由 Yandex 团队开发,旨在帮助开发人员更好地理解给定项目中 HTML 和 CSS 之间的关系。
以下是一个使用 BEM 风格的 CSS 开发人员可能编写的示例
/* Block component */
.btn {}
/* Element that depends upon the block */
.btn__price {}
/* Modifier that changes the style of the block */
.btn--orange {}
.btn--big {}
在这种 CSS 方法论中,块是新组件的顶级抽象,例如按钮:.btn { }
。这个块应该被认为是父元素。子元素或元素可以放置在其中,它们用块名称后的两个下划线表示,例如 .btn__price { }
。最后,修饰符可以操作块,以便我们可以对特定组件进行主题化或样式化,而不会对完全无关的模块造成影响。这可以通过在块名称后添加两个连字符来完成,例如 btn--orange
。
标记可能如下所示
<a class="btn btn--big btn--orange" href="https://css-tricks.org.cn">
<span class="btn__price">$9.99</span>
<span class="btn__text">Subscribe</span>
</a>
如果另一位开发人员编写了此标记,而我们不熟悉 CSS,我们仍然应该对哪些类负责哪些内容以及它们如何相互依赖有一个很好的了解。然后,开发人员可以构建自己的组件并根据自己的意愿修改现有块。无需编写太多 CSS,开发人员可能能够仅通过更改标记中的类来创建许多不同的按钮组合。
查看 CodePen 上由 CSS-Tricks (@css-tricks) 创建的 BEM 示例。
起初,这种语法可能看起来比简单地为每种类型的按钮创建一个新类要慢,但由于我们将要讨论的几个原因,事实并非如此。
为什么我们应该考虑 BEM?
- 如果我们要创建一个组件的新样式,我们可以很容易地看到哪些修饰符和子元素已经存在。我们甚至可能意识到我们根本不需要编写任何 CSS,因为已经存在一个可以满足我们需求的预先存在的修饰符。
- 如果我们正在阅读标记而不是 CSS,我们应该能够快速了解哪些元素依赖于另一个元素(在前面的示例中,我们可以看到
.btn__price
依赖于.btn
,即使我们还不知道它是什么)。 - 设计师和开发人员可以一致地命名组件,以便团队成员之间更容易沟通。换句话说,BEM 为项目中的每个人提供了一种他们可以共享的声明式语法,这样他们就可以站在同一立场上了。
Harry Roberts 发现 使用像 BEM 这样的语法时,在提高开发人员信心方面另一个关键优势。
这是我们最终得到臃肿的代码库,充满了遗留代码和未知 CSS 的主要原因,我们不敢去碰它们。我们缺乏能够使用和修改现有样式的信心,因为我们害怕 CSS 全局操作和泄漏性质的后果。几乎所有与 CSS 规模相关的问题都归结为信心(或缺乏信心):人们不再知道事物是如何运作的。人们不敢进行更改,因为他们不知道影响范围有多大。
同样,Philip Walton 认为 如果足够多的开发人员坚持 BEM 原则,这个问题可以得到解决。
虽然 100% 可预测的代码可能永远无法实现,但了解您在选择约定时所做的权衡取舍很重要。如果您遵循严格的 BEM 约定,您将能够在未来更新和添加 CSS,并且完全有信心您的更改不会产生副作用。
因此,如果开发人员能够更有信心地参与项目,那么他们一定会对这些视觉组件的使用方式做出更明智的决定。这种方法论可能不是解决所有这些问题的完美解决方案,但它确实为开发人员提供了一种标准,使他们能够在未来编写更好、更易于维护的代码。
BEM 的另一个巧妙之处在于所有内容都是类,并且没有任何内容是嵌套的。这使得 CSS 特定性非常平坦和低,这是一个好主意。这意味着您不会因特定性问题而互相争斗。
让我们来看看 BEM 的一些问题…
BEM CSS 的问题
当然,如果您违反了 BEM 规则,没有人会强迫您。您仍然可以编写这样的 CSS 选择器
.nav .nav__listItem .btn--orange {
background-color: green;
}
看起来它包含 BEM 的一部分,但它不是 BEM。它有嵌套选择器,而且修饰符甚至不能准确地描述正在发生的事情。如果我们这样做,我们将破坏对 BEM 非常有帮助的特定性平坦度。
一个块(如 .nav
)永远不应该覆盖另一个块或修饰符(如 .btn--orange
)的样式。否则,这将使我们几乎不可能阅读 HTML 并理解此组件的作用;在这个过程中,我们必然会严重损害另一位开发人员对代码库的信心。这对 HTML 也是如此:如果你看到了以下标记,你会期望什么?
<a class="btn" href="https://css-tricks.org.cn">
<div class="nav__listItem">Item one</div>
<div class="nav__listItem">Item two</div>
</a>
这里可能发生的情况是,完全无关的块中的一个元素具有开发人员所需的代码,但子元素不需要 .nav
类作为父元素。这会导致一个非常混乱和不一致的代码库,应该不惜一切代价避免。因此,我们可以总结这些问题:
- 永远不要在无关的块中覆盖修饰符。
- 避免在子元素可以独立存在时创建不必要的父元素。
更多 BEM 实践示例
手风琴演示
查看 CodePen 上由 CSS-Tricks (@css-tricks) 创建的 BEM 手风琴。
在这个示例中,有一个块,两个元素和一个修饰符。在这里,我们创建了一个 .accordion__copy–open
修饰符,它让我们知道我们不应该在另一个块或元素上使用它。
导航演示
查看 CodePen 上由 CSS-Tricks (@css-tricks) 创建的 BEM 菜单。
此导航演示包含 1 个块,6 个元素和 1 个修饰符。甚至完全可以创建没有修饰符的块。在未来的某个时刻,开发人员始终可以添加(或绑定到)新的修饰符,只要块保持一致即可。
不喜欢 BEM
也许您不喜欢双下划线或双连字符。没关系,使用其他一些独特且一致执行的符号。
以下是另一种观点
我不确定是否认同 BEM。.site-search .site-search__field .site-search–full 为什么不用:.site-search .site-search input .site-search .full
— Samuel Fine (@samuelfine) 2015 年 3 月 11 日
这最后三个选择器都具有不同的特定性级别。它们要么需要父元素,要么不需要。如果没有规则,它们不会像上面的规则那样明确。
这个微不足道且孤立的示例是否让您感觉良好,并且永远不会给您带来麻烦?也许吧。但是,项目中包含的 CSS 越多,这类小问题积累得越多,您遇到的特定性和复杂性问题也就越多。
如果您不知道 HTML 或 CSS 的工作原理,BEM 看起来非常有用。
— Samuel Fine (@samuelfine) 2015 年 3 月 11 日
这里不是要挑剔 Samuel,而是他的观点得到了很多人的认可,所以这是一个很好的例子。他们看到 BEM,就完全拒绝了它。如果您想不喜欢 BEM,那完全没问题,但我认为很难争辩说有一套规则可以帮助理解并有助于保持 CSS 可维护性是一个坏主意。
在 SMACSS 方法论中,您可能会发现一个包含三个字母的 CSS 类名。修饰符随后使用连字符跟随模块名称。
/* Example Module */
.btn { }
/* Modifier of the btn class */
.btn-primary { }
/* Btn Module with State */
.btn.is-collapsed { }
这仅仅是针对同一类问题的一种不同的命名方法。它非常相似,但您只是更明确地描述依赖关系并保持特定性更平坦。
在 OOCSS 中,块同样通用。
/* Example Module */
.mod { }
/* Part of Module */
.inner { }
/* Talk Module */
.talk { }
/* Variation of part inside Module */
.talk .inner { }
因此,你将在 HTML 中使用多个类来进行变体。内部部分没有像依赖项那样命名,因此不太清楚,但可能更可重用。BEM 会使用 .mod__inner
和 .mod--talk
以及 .mod--talk__inner
。
这些只是方法论上的变体。请记住,这里没有人强迫你,这些都是自我强加的规则,它们的价值来自遵循它们。
Sass 和 BEM
对于那些使用 Sass 并喜欢使用嵌套来限定样式的人,你仍然可以使用嵌套格式编写代码,但可以使用 @at-root
获取不嵌套的 CSS。
.block {
@at-root #{&}__element {
}
@at-root #{&}--modifier {
}
}
它会为你生成
.block {
}
.block__element {
}
.block--modifier {
}
你可以变得尽可能抽象!看看 Danield Guillan 的 BEM 构造器 或 Anders Schmidt Hansen 的 表达力强的 BEM。
总结
总结来说,我认为,尽管 BEM 无法解决我们所有的问题,但它对于构建可扩展和可维护的界面非常有用,团队中的每个人都应该清楚地了解如何改进这些界面。这是因为,大量的前端开发不仅仅是关于解决短期内一个小问题的巧妙技巧;我们需要在开发人员之间达成一致、承诺和有约束力的社会契约,以便我们的代码库能够随着时间的推移而适应。
通常,我认为 BEM 是对 Nicolas Gallagher 的问题的答案
将 "你能构建它吗?" 替换为 "你能在不失去理智的情况下维护它吗?"
—— Nicolas Gallagher (@necolas) 2013 年 7 月 24 日
我同意 Samuel 的观点,我不喜欢它。
我理解它的优缺点,但对我来说,缺点大于优点。
有时我们会给类名添加前缀,以便事物之间的关系很明显,例如
.form
.form-fieldset
.form-text
而不是
.form
.form fieldset
.form input[type=text]
但那是我们所能做的。我对连字符和下划线背后的理念感到有点混乱和困惑。
是的,连字符和下划线看起来很奇怪
对我来说,它似乎让查看一个元素并判断其所有(或至少大部分)样式来自哪里变得容易多了。
在上面的
.form-fieldset
示例中,如果我想在form
中使用一个特殊的fieldset
,使其变为绿色,现在我有.form-fieldset-green
,这表示一个在form
内部的绿色fieldset
,还是一个在form
内部的fieldset
内部的元素上的绿色类?对我来说,
__
表示元素之间的区别,而--
表示修饰符之间的区别,这非常有效。现在我知道.form__fieldset--green
是一眼就能看出的form
内部的绿色fieldset
。同意,不要回到 2006 年,让我们给自己准备一些巨大的类汤
前段时间我偶然发现了这个:https://github.com/rstacruz/rscss。开始使用它,在我看来,它比很多下划线等等更清晰。代码也看起来更干净。
使用 BEM 进行重构更容易。没有连字符和下划线,我敢打赌你将不得不用嵌套,而嵌套会导致级联覆盖和重命名或删除类时的不确定性。你也不容易在新的地方重用嵌套类,你将不得不再次进行重构。
这里你可以找到更多关于该主题的详细信息,并附有示例。
我是 BEM 的忠实粉丝。过去两年我一直在我所有的办公室和个人项目中使用 BEM。BEM 从来没有令人头疼,尤其是在处理大型项目和大型团队时。HTML 看起来干净、可读且易于理解。有助于为样式表创建完美的模块化。有助于并倾向于编写或开发更多模块化代码。在 Sass 或 Less 的帮助下,你可以将网站创作变成一种很棒的体验。
我大多数朋友都抱怨下划线和长名称看起来很奇怪,需要输入更多内容,很多废话等等。但我从自己的经验中看到了主要的好处
可理解的 HTML 文档
帮助你编写模块化样式表
易于维护样式表
BEM 使你将网页视为组件的组合
这有助于创建可重用的样式表
BEM 在处理类名时提高了 JavaScript 代码的可读性。
我从 BEM 获得的最大好处是,它训练我以模块化的方式思考。不仅是 CSS,还有编程。我能感受到这种变化以及我获得的优势。我不知道该怎么解释,是的,这是真的。
尝试一下吧。
和平
SCSS 和 BEM 对我来说很有效,我通常会编写类似这样的代码
问题
如果你有…
…并且需要使用 Ctrl+F 搜索
.block__title
?难道让所有类都易于搜索不是更有意义吗?嵌套看起来更干净,但我认为无法使用 Ctrl+F 搜索代码库中的内容确实是一个缺点。BEM(和其他组件方法论)提倡一个组件一个文件的方式。因此,查找内容从打开该组件的文件开始(Ctrl-P 或 Ctrl-T 或编辑器具有的任何“导航到文件”快捷键)。这很棒,因为它立即缩小了搜索范围。如果文件太大而无法用肉眼扫描,你只需使用 Ctrl+F 搜索
&__title
即可。@Jeremy – @Mike 的总结非常到位。由于块已正确命名,并且你的文件结构逻辑合理,你不会在查找所需内容时遇到困难。在使用之前我也有同样的担心,但现在已经不再回头了。选择最适合你和你项目的文件结构,并在 Sublime 中使用 Ctrl+Shift+F 快速跨多个 .scss 文件查找类。映射也可以帮助你。
感谢大家。这说得通。
最新的 Sass 版本以以下方式支持 BEM
这将导致
你可以在线查看它 – http://sassmeister.com/gist/fe753a8228da9ed45136
相同的语法也适用于 LESS。如果任何 LESS 用户有疑问。
不需要
@at-root #{&}__element
,因为&__element
在 sass 中也有效。一开始我不喜欢 BEM 的冗长外观,但它让我很快适应了。现在,我更容易通过查看 BEM CSS 来理解结构,它也有助于我想出命名方法。
我个人很喜欢这个:https://github.com/rstacruz/rscss
它在选择器中增加了一点深度,但它纠正了 BEM 中让我困扰的一件事:类标题的长度。
我不知道舒适的选择器在多大程度上与深度相关,但我确实更喜欢它。
我在最近的几个项目中使用 BEM,我认为它很有效。我唯一不同的是交换了下划线和连字符,因为我更喜欢连字符,我的 CSS 通常包含的元素比修饰符更多。
我喜欢BEM。一开始我避开它,因为 *它太丑了*,但后来我意识到我可以使用mixins来抽象css中的格式。在scss中,它比它值钱的字符更多,但在缩进的sass中,它有点美观。
优雅地编译成
以下是有那些漫无目的的mixins
我喜欢这种方法。谢谢,夏洛特。
嗨,伙计们,你们觉得以下采用类似方法的库怎么样?
https://github.com/danielguillan/bem-constructor
这看起来很棒!谢谢夏洛特 :)
看起来很棒,谢谢!
即使我也不喜欢这个……也许我们可以使用骆驼命名法。
.btn {}
/* 依赖于块的元素 */
.btnPrice {}
这将有助于在js中也维护代码模式……。
Sass + BEM是使用BEM的一个很好的理由。两者似乎都是为了编写 *你不会被搞糊涂* 的CSS。
我想我的BEM更多的是 .parent-child,我很少使用修饰符,如果有的话。我开始用 `l_` 前缀编写高级布局块,比如
BEM会更像是 `l_header__nav`,但我使用破折号仅仅是因为如果我想选择选择器的任何元素,破折号更适合在文本编辑器中双击。(下划线是单词字符,所以双击会选择整个选择器。)也许这是一种奇怪的理由,但它有助于我的工作流程。
我将插一句,因为,出于我的罪过,我发现CSS架构永远迷人。
恕我直言,任何试图使HTML类和CSS选择器合理化和强制执行的方法都比没有系统要好。系统/UI越复杂,这一点就越真实。
你可能不喜欢BEM语法(我不是粉丝),但这些原则比根本不使用系统(特别是在规模上)为你带来更多的东西。
我同样不喜欢在Sass中使用父选择器进行嵌套的做法;你失去了与你的标记的一对一关系(你不能从开发工具中选择一个HTML类并在Sass代码库中搜索选择器)。
对于非常大的复杂UI(以及取决于你构建它们的方式),我发现不同的方法更有利(我称之为我自己的 持久的CSS)比BEM,主要是使用微命名空间作为一种包含手段。我发现实践中,它更健壮,迭代速度更快,从命名角度看更容易理解(最后一点完全是主观的)。
无论你选择什么,无论你如何从你开始的方式进行调整,拥有某种方法总比没有定义的方法好得多!
嘿,Ben,如果你将Sass文件结构化,使每个块都有自己的文件夹和自己的 `scss` 文件,那么通过选择器进行搜索就不再必要,因为查看 `footer__copyright` 将立即带你到 `footer` 文件夹,而无需任何搜索,然后只需在该特定文件中找到 `__copyright` 即可 :)
“你不能从开发工具中选择一个HTML类并在Sass代码库中搜索选择器。”
使用源映射……。
@Alex 我目前使用Sublime,我可以双击DOM中的HTML类,CMD+C,然后在Sublime中CMD+R和CMD+V来查找该项目范围内的符号。在不到一秒的时间内,它会直接将我带到Sass/CSS中的那个选择器,准备输入。我发现这比手动浏览组件文件夹(我拥有超过100个组件)快得多。
@ewfwefewfewewf - 源映射意味着我需要在浏览器中编辑。我更喜欢在我的文本编辑器中编辑。
题外话 -
@Ben Frain
虽然你可以 在浏览器(Chrome)中编辑 并保存文件,但这是一种浏览器功能,而不是源映射功能。
我在文本编辑器中编辑并使用源映射的方式
启用源映射(Chrome).
查看特定规则在源/预处理文件中的位置。
编辑。
如果你使用Sublime Text,你不需要“找到”该规则,只需按下 `CTRL+G`(Windows)并键入行号。
为了澄清你关于SMACSS的观点,如果 `callout` 是 `module` 的变体,它应该命名为 `module-callout`。
BEM和SMACSS之间几乎没有区别。在SMACSS中,它谈论模块、子模块和子组件。这些直接对应于块、修饰符和元素。
这里有没有一个开发人员实际上在一个项目中使用了BEM,而不是加入它?很容易因为它“看起来很奇怪”或者你“不喜欢 __ 或 - ”而把它打发掉,但这只是我们已经知道的“最佳实践”的遗留思想,这些最佳实践并不一定总是最佳的。项目越大,参与的人越多 - BEM之类的東西的好处就越大。
至于Sam的推文,你真的会感觉舒服地加入一个项目并更改`.full` 规则吗?我高度怀疑这一点,这将导致更高的特异性选择器,并且随着项目的增长,一致性/可维护性会降低。(这会浪费时间和金钱,看起来也不好)
试一试,你可能会感到惊讶。
没错,一旦你放弃任何最初的顾虑,并在一个项目中真正开始使用这种方法,你会惊讶地发现它变得多么有用,以及不使用它看起来多么奇怪。
我挑战任何反对者在一个项目中试一试,我认为你将会惊讶于它如何改变你对CSS的看法。一旦你理解了它,它几乎是必不可少的。
就是这样。在使用过几个带有BEM(和SASS)的项目之后,我意识到类名和冲突的错误明显减少了。它只是那些潜移默化地让我喜欢上的东西。
我喜欢它的一点是,我可以安全地使用通用词语(块、区域、容器)作为BEM-元素名称。当我不必费心去想新的名字时,它确实加快了开发速度。
而且,就像许多人在这里提到的那样,@at-root可以用新的SASS版本删除。像这样
关于BEM的精彩文章。我发现人们对它有不同的意见,这很好,体现了css的表现力。
我发现BEM既可扩展又可读(这就是我们使用它的原因)。一开始我们纯粹使用它来识别父子关系,我很难找到修饰符的用处,但我们使用得越多,就越意识到,使用得当,你可以构建极其灵活和精简的架构!
如果有人感兴趣,我写了一个小的WordPress脚本,用于创建动态BEM菜单,(如果你喜欢BEM)我相信你会欣赏用BEM语法创建复杂的多级导航比使用 `menu-name li > ul > li{}` 方便多少。
如果你以前从未使用过BEM,它可以作为一个实际的使用示例
https://github.com/roikles/Wordpress-Bem-Menu
太啰嗦了,看起来也很奇怪。将下划线与双破折号、单破折号和骆驼命名法混合使用。不,先生。只使用单破折号表示继承和子级别元素效果非常好,看起来不奇怪也不啰嗦,并且不会诱导你编写过于具体的选择器。
感谢Joe、Robin和大家写了一篇很棒的文章。
根据我的经验,它很大程度上取决于给定项目的复杂程度、个人偏好(我的心理模型)以及我所在的团队。
有些项目太小(不是很复杂),使用BEM式方法没有意义,而其他需要高度模块化的项目,根据我的经验,从BEM中受益匪浅。
就我所在的初创团队而言,当事情非常基于组件并遵循BEM时,这使得我们更容易讨论和理解我们的代码。好吧,这是 **“罗伯茨遇到加拉格尔遇到斯努克遇到我们自己的混合”** 版本的BEM。
对我们来说,我们需要事物非常像乐高积木 - 能够独立移动,轻松地移除或添加 - 因为我们需要根据客户反馈和用户测试结果快速迭代。BEM在这方面帮助了我们很多。
说实话,当我第一次看到BEM时,我并没有信服,但试用过之后,我开始真正喜欢它。也许就像React的 **“给它五分钟”** 一样。
BEM的所有好处对我来说都有道理,我喜欢它。我对它最大的抱怨是类名变得非常非常长。尤其是你进入模块的更深处。
例如,假设以下HTML/CSS
.accordion
.accordion__title
.accordion__title__icon
然后假设我想在`.accordion__title__icon` 上添加一个修饰符 -
class=”accordion__title__icon accordion__title__icon–facebook”
我知道我们可以缩短类的名称,但这有点违背了让所有开发人员都能快速理解代码的初衷。
使用BEM时,你应该避免使用像“accordion__title__icon accordion__title__icon–facebook”这样的代码。
你最好将“accordion”和“icon”作为单独的组件。然后将它们组合起来。
这样做的好处是,它们可以在网站的其他地方使用,而无需依赖彼此。目标是将每个部分抽象化,以便它可以在其他地方独立使用。
嘿,Neal,我同意@Andrew H的观点,你通常不需要嵌套得那么深。如果你在一个元素里面有一个元素,那么最上面的元素可能是一个单独的块。我曾经写过一篇关于BEM mixins的文章,如果你感兴趣,请看看。
我同意上面几位。但是我不喜欢将基本类和修饰符类一起指定的模式,它真的很冗余(
class=”accordion__title__icon accordion__title__icon–facebook”
)。这里你可以了解一个简单的解决方法。
我赞成强制一致性并使用命名规范,但双下划线看起来很糟糕,尤其是与单/双连字符结合使用时。
一个经常被误解的是,BEM 特别要求双下划线或连字符。那是他们的默认建议,以便支持连字符分隔的名称,例如
.menu-button__submit-icon
。但采用帕斯卡命名法也是有效的,例如.menuButton_submitIcon
。请参阅他们文档中的示例。我建议你阅读 Harry Roberts 在 Smashing Book #4 中写的“现代 CSS 架构和前端开发”。
如果你喜欢 BEM 的概念但不喜歡语法,还有其他选择,比如 SUIT:https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md
我更进一步。我在 CSS 中使用命名空间。
Harry 在这里展示了其中的一些好处:(Harry 有没有在这里做过客座博客?他应该来。试试让他来。)
http://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/
我只有一处修改。我使用的是“.namespace-block-element–modifier”,因为下划线太容易被忽略了。
看起来 CSS 中的第一个“C”是最可怕的…… :-)
这是合理的,因为你无法阻止级联。
对于那些不喜欢写长 CSS 类名的朋友们,不要用手写,试试 BH 模板引擎:http://bem.github.io/bh/
这段模板代码
应用于这个 json
将生成这个 html
看在上帝的份上,我希望这不会流行起来。
它丑陋得像罪恶一样,感觉就像回到了2004年。
如果使用得当,特异性并非你的敌人。
所有关于双下划线“丑陋”的评论似乎都忽略了重点。无论它是否丑陋,BEM 都清楚地表明了其意图。清晰度和结构是重点,而不是标记和 CSS 的美观与否。
@Brendan,我在项目中使用过它,结果更加不喜欢它。这是对 CSS 的滥用。人们甚至可以进一步声称它基本上违背了 CSS 的一些核心原则。
它可能在某些地方有用,但已经被过度使用。
首先,为你在判断之前尝试过它点赞。但是,我强烈反对 BEM 是滥用,或与 CSS 相反。你能详细说明一下这种强烈的观点吗?
CSS 是一套模糊的规范。它独特的设计目标包括紧凑性、设备无关性和发布者与用户之间的共享权限(事实证明,这在长期内并不重要)。BEM 中没有任何内容与这些原则相矛盾。BEM 只是为 CSS 添加了“协作组件化”:规则按逻辑分组在一起,每个组都遵循一组关于选择器构建的严格约束。
除了
ugly__syntax--conventions
(可以更改)之外,我最大的反对意见是你的 HTML 中有一系列类名,例如class="btn btn--big btn--orange"
这样你就有了很多可以自由组合的变体……但这有助于你的网站获得一致的风格吗?如果你不根据大小或颜色等特征来命名类,而是根据功能来命名,也许突然之间有意义的组合会大大减少。
而且其中很多可以通过为父元素提供一个合理的类来完成。为什么要让按钮变大?因为用户有触摸设备吗?那么就为 body 提供
.touchDevice
类,这样就可以同时调整更多元素。是的,这会创建特异性,但正如 el generico 所写:如果使用得当,它并非你的敌人。如果可能并且不至于太混乱,我会尝试将我的类分组在 CSS 中,这样我就不必重复定义基本内容。示例
这样我就不必写
class="btn btn-deactivated"
,只需要写class="btn-deactivated"
就够了。类名中包含了样式中的内容,即 btn 和 deactivated。我喜欢我的 CSS 和 HTML 简洁明了。类链显然不是我的菜。
耶,终于找到了另一个与我观点相同的人!我现在太高兴了:) 请看看我的文章,它描述了另一种使用属性选择器来对修饰符类进行分组的方法。我想知道你的想法。
Sergey,使用 CSS 选择器
[class^="block--"], [class*=" block--"]
的想法很棒。这样你也可以缩短 CSS 文件中的类列表。我在一个由等效幻灯片组成的网站上使用了类似的东西。使用
[class^="slide-"]
,我为所有幻灯片提供了基本样式;而使用.slide-1
、.slide-2
、.slide-3
等,我设置了诸如背景图像之类的单个属性。当然,你可以在 BEM 方法中编写简明扼要的 CSS。
一种方法是使用像 SASS 这样的预处理器,这样你就可以明确地定义你的样式指南。
你也可以使用完整的 BEM 堆栈,从而避免手动编写 HTML。
我们不能在 CSS 中也使用部分属性选择器吗?
[class*=–disabled]{pointer-events:none;}
这不会覆盖任何 .block–disabled 项吗?
好问题。“disabled”的语义在不同的逻辑环境中可能意味着不同的东西。如果我们说的是一个输入字段,disabled 可能会意味着“此控件为只读”。在 BEM 块所支持的更高抽象级别上,我们可能在 Product Listings 块中有一个 Product 块的列表。这样的 Product 本身可能具有“disabled”状态,这可能意味着“此产品因缺货而不可售”。“disabled”这两个定义是不同的,并且将具有不同的表示含义。
根据你的建议,我们在代码设计中忽略了逻辑上下文,并且不允许它。我们假设“disabled”这个词具有一个共同的含义,无论它应用于哪个上下文。最终,这会阻碍在更高抽象级别上工作,因为在级联中重新定义类名的含义会很麻烦且痛苦。没有抽象,我们就不得不从低级 HTML 原语的角度来思考整个前端,这会浪费我们有限的认知能力。最坏的情况是,它会耗尽这种能力,使前端难以理解、不可预测且容易出现回归。
我希望这篇文章能解决我对 BEM 的主要不满(我否则很喜欢它),这有时会导致我写出像
section-name__content__blurbs__blurb__title
这样的超长类名。如何决定什么是块? 整个页面肯定不是一个单独的块,但是如何决定如何分解它?
如何命名那些仅仅是为了实现一些 CSS 技巧或功能而存在的元素? 想象一下你有一个
hero
元素,它在视觉上只包含一个headline
和一个tagline
作为其显式子元素。你希望你的类名为.hero
、.hero__headline
和.hero__tagline
,但你需要一些中间元素来实现一些设计目标(例如包装器、用于垂直居中的预 flexbox 容器——发挥你的想象力)。这些元素需要样式,所以你是否被迫写成.hero__wrapper__container__headline
? 有时候我会这样做,但我也认为这是对整个命名规范的荒谬缩减。其他时候我会用“包装器元素与其说是父元素的子元素,不如说是模块实现的一部分,所以我叫它.hero--wrapper
并且将子选择器的长度减少一个。”但这会削弱命名规范。命名空间。需要一个技巧来使代码工作? 在前面加上“_”。
http://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/
“如何决定什么是块?”
任何自包含且可以分解的元素。如果你可以把它移动到页面的任何地方,并且它在任何地方都能像它在其他地方一样工作。那就是一个块。导航、内容区域、侧边栏、页脚、页眉、轮播等。
Zack,没有必要在元素的名称中镜像嵌套结构。
Hero
布局可以是这样的除非你在不同的嵌套级别上拥有相同名称的元素(这本身不是一个好主意),否则你仍然获得了针对 CSS 选择器冲突的防弹保护。
Roman,我从未见过用更经典和语义的方式布局存在问题
因此,LESS 或 SCSS 代码看起来像这样
干净简洁,不是吗?
这种布局很容易被嵌套块破坏,因为 block1 的选择器会影响 block2 元素。
BEM 命名可能并不那么干净和简单,但它保证了防弹封装。
我 fork 了第一个笔,提供一个简短的 BEM 模板示例:http://codepen.io/sameoldmadness/pen/yyWXZm?editors=001
看到评论中围绕“正确”类名的很多讨论令人沮丧。
毕竟,BEM 并没有告诉你如何命名你的类。相反,它提出了一种将你的代码分离成原子可重用组件的方法。
只要看看 BH 语法中的基本块声明
它与 HTML、CSS 或 JS 无关。
但块本身可以包含所有这些技术(甚至更多)中实现的逻辑。
对于
.mod--talk__inner
示例,我更倾向于尽可能地将修饰符保持在块上。所以,这将是否则,你需要为块的每个元素创建一个新的修饰符类。
我想这会影响特异性,但 .mod–talk .mod__inner 应该始终具有优先级。
但是,我想这引发了一个问题:元素应该嵌套在块中吗?
你对第一块代码的观点非常到位——只有在修饰符中嵌套它们,或者作为单独的修饰类,例如
.mod__inner--wide {}
以下内容将是多余的,因为
.mod__inner
的命名方式表明我们已经知道它是一个.mod
元素随着组件的开发,你将减少与特异性斗争的次数。
首先,我希望无论你使用 BEM 与否,你都将 CSS 模块化。其次,看看你当前的项目。你是否经常将不相关的模块嵌套在你的模块中?如果是这样,那么使用 BEM 方法。如果不是,使用一种使 HTML 和 CSS 更具可读性的方法。
我编写了 Title CSS 作为一种轻松定位模块类并为短后代类创建作用域的方法。 https://github.com/cuth/Title-CSS
我发现,在示例中使用“orange”作为类名确实是一个糟糕的主意。
因为,当然有人会写
.sidebar .orange { color: blue; }
,无论 BEM 与否。为什么不使用
.primary
或.secondary
呢?这里有一位优秀的博主解释了语义化 CSS。
我经常从后端人员那里得到反馈,说使用 BEM 会给他们带来更多工作,项目经理也不喜欢听到这种说法。他们的论点是,对于他们来说,输出
而不是
<
form class=”signup__sidebar”>
等等
更容易,因为第一个变体已经以这种方式从 CMS 中输出,而第二个需要更多编码工作才能实现。这不仅仅是关于表单,还包括他们用于 CMS 的任何其他插件/扩展。
应该如何看待这个问题?
在我上面的例子中,第一个变体是
第二个变体是
我只是称它为 .butts,指的是按钮。
所以它应该是这样的:
.butts {}
.butts>span:first-of-type {}
.butts>span:last-of-type {}
我不知道为什么你会给这些家伙的子元素加上类。
在我看来,BEM 简直是疯了,它使 HTML 和 CSS 代码变得奇怪。
好吧,即使你的项目非常复杂,有很多内容由多个团队交付,为什么不遵循 Web Components 方法,它可以使一切保持清晰和简单? http://webcomponents.org/
因为浏览器不支持它。而且 polyfills 速度很慢。
所以,如果我遵循这种结构,这对于导航元素是否合适?
而且,什么是过犹不及?假设例如我在链接中有一些小型样式元素,例如图标,这会添加第四层吗?在处理 BEM 时,界限在哪里?你能走得太远吗?
不。
正确的代码应该是
@Sergey——你把元素和修饰符搞混了
试试这个
谢谢 David!我只会规范 BEM 命名
这篇文章完美地揭示了开发人员无法正确理解 BEM 规范。
我使用自己的系统,因为我不喜欢 BEM 类名。我理解整个单选择器的东西,但我发现使用更短的类名创建模板要快得多。
子元素类名总是以双下划线开头,修饰符以单个破折号开头。我发现这在 HTML 和 SCSS 中都更容易阅读,例如
HTML
SCSS
我做了类似的事情,但在内部选择器中使用了子组合器。否则,你将在组合组件时暴露自己,面临回归和选择器冲突的风险。例如,如果这个 Accordion 最终组合了一个 ArticleBlurb,它可能拥有自己的 __content,那么 Accordion 的 __content 样式将应用于 ArticleBlurb 的。这可以通过子组合器轻松解决
你失去了将任意元素添加到 Accordion 结构中的灵活性,但这是一种功能而不是错误。一致的结构使组件更容易管理。
Knappster,我也使用相同的嵌套样式(以及 Mike),但我的命名规范不同。
由于“Accordion”和所有其他模块类都以大写类名开头,我可以随意使用任何小写名称来命名后代类,因为类名是区分大小写的。
有关此命名规范的更多信息:http://www.sitepoint.com/title-css-simple-approach-css-class-naming/
请记住,我们也应该关注 CSS 的效率。我认为,在必要时,效率应该胜过我们的开发便捷性。
https://mdn.org.cn/en-US/docs/Web/Guide/CSS/Writing_efficient_CSS
Nick,我强烈不同意。“过早优化是万恶之源。” 项目中,无序的 CSS 通常比未优化的选择器带来的风险更大。性能/效率是否需要关注和理解? 是的。但它不应该是首要目标。只有在必要时才进行优化。与大多数编程语言不同,CSS 在这方面是一项特别敏感的软件技术,因为它没有提供强大的抽象机制来隐藏复杂的优化。
也就是说,除了选择器之外,还有其他方法可以优化呈现。限制阴影和透明度的使用。优先使用 CSS3 过渡/动画而不是 JavaScript 动画。合并样式表以减少 HTTP 开销。
有道理,我认为我的示例有点过于简单了。
对于响应式设计中的断点来说,这对于新手网页设计师和开发者来说很有用。因为代码更简洁。