BEM —— 源自Yandex的CSS 命名方法论

时间:2022-08-31 17:42:45

原文链接: https://segmentfault.com/a/1190000000391762

人们问我最多的问题之一是在CSS类名中--__是什么意思?它们的出现是源于BEMNicolas Gallagher...

BEM —— 源自Yandex的CSS 命名方法论

BEM的意思就是块(block)、元素(element)、修饰符(modifier),是由Yandex团队提出的一种前端命名方法论。这种巧妙的命名方法让你的CSS类对其他开发者来说更加透明而且更有意义。BEM命名约定更加严格,而且包含更多的信息,它们用于一个团队开发一个耗时的大项目。

重要的是要注意,我使用的基于BEM的命名方式是经过Nicolas Gallagher修改过的。这篇文章中介绍的这种命名技术并不是原始的BEM,但却是一个我更喜欢的改进版。无论实际使用了什么样的符号,它们其实都是基于同样的BEM原则。

命名约定的模式如下:

.block{}
.block__element{}
.block--modifier{}
  • .block 代表了更高级别的抽象或组件。
  • .block__element 代表.block的后代,用于形成一个完整的.block的整体。
  • .block--modifier代表.block的不同状态或不同版本。

之所以使用两个连字符和下划线而不是一个,是为了让你自己的块可以用单个连字符来界定,如:

.site-search{} /* 块 */
.site-search__field{} /* 元素 */
.site-search--full{} /* 修饰符 */

BEM的关键是光凭名字就可以告诉其他开发者某个标记是用来干什么的。通过浏览HTML代码中的class属性,你就能够明白模块之间是如何关联的:有一些仅仅是组件,有一些则是这些组件的子孙或者是元素,还有一些是组件的其他形态或者是修饰符。我们用一个类比/模型来思考一下下面的这些元素是怎么关联的:

.person{}
.person__hand{}
.person--female{}
.person--female__hand{}
.person__hand--left{}

*块是‘person’,它拥有一些元素,如‘hand’。一个人也会有其他形态,比如女性,这种形态进而也会拥有它自己的元素。下面我们把他们写成‘常规’CSS:

.person{}
.hand{}
.female{}
.female-hand{}
.left-hand{}

这些‘常规’CSS都是有意义的,但是它们之间却有些脱节。就拿.female来说,是指女性人类还是某种雌性的动物?还有.hand,是在说一只钟表的指针(译注:英文中hand有指针的意思)?还是一只正在玩纸牌的手?使用BEM我们可以获得更多的描述和更加清晰的结构,单单通过我们代码中的命名就能知道元素之间的关联。BEM真是强大。

再来看一个之前用‘常规’方式命名的.site-search的例子:

<form class="site-search  full">
<input type="text" class="field">
<input type="Submit" value ="Search" class="button">
</form>

这些CSS类名真是太不精确了,并不能告诉我们足够的信息。尽管我们可以用它们来完成工作,但它们确实非常含糊不清。用BEM记号法就会是下面这个样子:

<form class="site-search  site-search--full">
<input type="text" class="site-search__field">
<input type="Submit" value ="Search" class="site-search__button">
</form>

我们能清晰地看到有个叫.site-search的块,他内部是一个叫.site-search__field的元素。并且.site-search还有另外一种形态叫.site-search--full

我们再来举个例子……

如果你熟悉OOCSS(面向对象CSS),那么你对media对象一定也不陌生。用BEM的方式,media对象就会是下面这个样子:

.media{}
.media__img{}
.media__img--rev{}
.media__body{}

从这种CSS的写法上我们就已经知道.media__img 和.media__body一定是位于.media内部的,而且.media__img--rev.media__img的另一种形态。仅仅通过CSS选择器的名字我们就能获取到以上全部信息。

BEM的另外一个好处是针对下面这种情况:

<div class="media">
<img src="logo.png" alt="Foo Corp logo" class="img-rev">
<div class="body">
<h3 class="alpha">Welcome to Foo Corp</h3>
<p class="lede">Foo Corp is the best, seriously!</p>
</div>
</div>

光从上面的代码来看,我们根本不明白.media和.alpha两个class彼此之间是如何相互关联的?同样我们也无从知晓.body和.lede之间,或者.img-rev
和.media之间各是什么关系?从这段HTML(除非你对那个media对象非常了解)中我们也不知道这个组件是由什么组成的和它还有什么其他的形态。如果我们用BEM方式重写这段代码:

<div class="media">
<img src="logo.png" alt="Foo Corp logo" class="media__img--rev">
<div class="media__body">
<h3 class="alpha">Welcome to Foo Corp</h3>
<p class="lede">Foo Corp is the best, seriously!</p>
</div>
</div>

我们立马就能明白.media是一个块,.media__img--rev是一个加了修饰符的.media__img的变体,它是属于.media的元素。而.media__body是一个尚未被改变过的也是属于.media的元素。所有以上这些信息都通过它们的class名称就能明白,由此看来BEM确实非常实用。

丑极了!

通常人们会认为BEM这种写法难看。我敢说,如果你仅仅是因为这种代码看上去不怎么好看而羞于使用它,那么你将错失最重要的东西。除非使用BEM让代码增加了不必要的维护困难,或者这么做确实让代码更难读了,那么你在使用它之前就要三思而行了。但是,如果只是“看起来有点怪”而事实上是一种有效的手段,那么我们在开发之前当然应该充分考虑它。

是,BEM看上去确实怪怪的,但是它的好处远远超过它外观上的那点瑕疵。

BEM可能看上去有点滑稽,而且有可能导致我们输入更长的文本(大部分编辑器都有自动补全功能,而且gzip压缩将会让我们消除对文件体积的担忧),但是它依旧强大。

用还是不用BEM?

我在我的所有项目中都使用了BEM记号法,因为它的有效性已经被它自己一次又一次地证明。我也极力地建议别人使用BEM,因为它让所有东西之间的联系变得更加紧密,让团队甚至是你个人都能够更加容易地维护代码。

然而,当你真正使用BEM的时候,重要的是,请记住你没必要真的在每个地方都用上它。比如:

.caps{ text-transform:uppercase; }  

这条CSS不属于任何一个BEM范畴,它仅仅只是一条单独的样式。

另一个没有使用BEM的例子是:

.site-logo{}    

这是一个logo,我们可以把它写成BEM格式,像下面这样:

.header{}
.header__logo{}

但我们没必要这么做。使用BEM的诀窍是,你要知道什么时候哪些东西是应该写成BEM格式的。因为某些东西确实是位于一个块的内部,但这并不意味它就是BEM中所说的元素。这个例子中,网站logo完全是恰巧在.header的内部,它也有可能在侧边栏或是页脚里面。一个元素的范围可能开始于任何上下文,因此你要确定只在你需要用到BEM的地方你才使用它。再看一个例子:

<div class="content">
<h1 class="content__headline">Lorem ipsum dolor...</h1>
</div>

在这个例子里,我们也许仅仅只需要另一个class,可以叫它.headline;它的样式取决于它是如何被层叠的,因为它在.content的内部;或者它只是恰巧在.content的内部。如果它是后者(即恰巧在.content的内部,而不总是在)我们就不需要使用BEM。

然而,一切都有可能潜在地用到BEM。我们再来看一下.site-logo的例子,想象一下我们想要给网站增加一点圣诞节的气氛,所以我们想有一个圣诞版的logo。于是我们有了下面的代码:

.site-logo{}
.site-logo--xmas{}

我们可以通过使用--修饰符来快速地为我们的代码构建另一个版本。

BEM最难的部分之一是明确作用域是从哪开始和到哪结束的,以及什么时候使用(不使用)它。随着接触的多了,有了经验积累,你慢慢就会知道怎么用,这些问题也不再是问题。

结束语

所以,BEM(或BEM的变体)是一个非常有用,强大,简单的命名约定,以至于让你的前端代码更容易阅读和理解,更容易协作,更容易控制,更加健壮和明确而且更加严密。

尽管BEM看上去多少有点奇怪,但是无论什么项目,它对前端开发者都是一个巨有价值的工具。

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

扩展阅读

by 大漠

  1. Yandex BEM/OOCSS
  2. Template Components点击预览
  3. BEM: The Block, Element, Modifier Approach To Decoupling HTML And CSS
  4. CSS methodology and frameworks
  5. Maintainable CSS with BEM
  6. A New Front-End Methodology: BEM
  7. What is BEM?
  8. Rubbing Noses With inuit.css
  9. SMACSS: Notes On Usage
  10. What is BEM?
  11. The History of BEM
  12. Start developing BEM with project-stub

原文 MindBEMding – getting your head ’round BEM syntax

翻译 David

BEM —— 源自Yandex的CSS 命名方法论的更多相关文章

  1. BEM --Yandex的CSS 命名方法论

    人们问我最多的问题之一是在CSS类名中--和__是什么意思?它们的出现是源于BEM和Nicolas Gallagher... BEM的意思就是块(block).元素(element).修饰符(modi ...

  2. BEM(一种 CSS 命名规则)

    一. 什么是 BEM BEM的意思就是块(block).元素(element).修饰符(modifier),是由 Yandex 团队提出的一种前端命名方法论. 这种巧妙的命名方法让你的 CSS 类对其 ...

  3. CSS命名方式&equals;》BEM

    时间:2016-11-04 20:04:53 原文地址:https://github.com/zhongxia245/blog/issues/48 一.背景 挺早就听说过BEM了,也大概的知道怎么用, ...

  4. CSS命名规范——BEM思想(非常赞的规范)

    人们问我最多的问题之一是在CSS类名中“--”和“__”是什么意思?它们的出现是源于BEM和Nicolas Gallagher... BEM的意思就是块(block).元素(element).修饰符( ...

  5. 前端css命名规范----BEM

    一.什么是BEM BEM就是块(block).元素(element).修饰符(modifier),是由Yandex团队提出的一种前端命名方法论.这种巧妙的命名方法可以使css类对其他开发者来说更加透明 ...

  6. CSS 命名规范 BEM 思想

    Part.1 何为 BEM? BEM :Block ( 块 ) 丶Element ( 元素 ) 丶Modifier ( 修饰符 ) 出 处:是由 Yandex 团队提出的一种前端命名方法论 优 点:命 ...

  7. CSS 命名管理 之 BEM

    好吧,将 BEM 简单的解释为 “Block-Element-Modifier“, 其实是个不负责任的做法.鬼知道 Block 是什么啊?所以,看了一些似懂非懂的中文解释之后,自己还是得去找些英文来读 ...

  8. css命名规范: BEM 的命名法

    整理自:前端早读课[第1183期]这些 CSS 命名规范,将省下你大把调试时间 试图解决 3 类问题: 仅从名字就能知道一个 CSS 选择器具体做什么 从名字能大致清楚一个选择器可以在哪里使用 从 C ...

  9. css命名管理混乱?不妨试试BEM

    css的缺陷 我们知道,css使用中一个比较令人烦恼的问题,就是css没有作用域可言,我们写了一个组件或者模块之后,往往希望它们可以四处复用,但是由于css没有作用域,我们给样式命名的时候都会非常小心 ...

随机推荐

  1. &lbrack;SharePoint 2007&sol;2010&rsqb;Query SharePoint Calendar Event

    首先要搞清楚日历事件的各种类型,参考文章: http://sharepoint.microsoft.com/blog/Pages/BlogPost.aspx?PageType=4&ListId ...

  2. 论使用LeanCloud中遇到的坑

    1.短信验证码 当注册用户的时候,会发现收不到短信验证码,打印e : That operation isn't allowed for clients. 含义 - 该操作无法从客户端发起.请检查该错误 ...

  3. NSMutableAttributedString&sol;NSAttributedString 富文本设置

    今天在做项目的过程中,我们的设计师想要一种字体四周都带阴影的效果,但是我们平时使用的setShadowColor 和setShadowOffset是达不到这种效果,setShadowOffset 只能 ...

  4. 运用JMX监控Tomcat&sol;Java jvisualvm简要说明

    公司线上项目出现了java heap space 然后经过查询知晓了下面工具于是开始了尝试. visualvm能干什么:监控内存泄露,跟踪垃圾回收,执行时内存.cpu分析,线程分析... jvisua ...

  5. 写一个EF的CodeFirst的Demo

    写一个EF的CodeFirst的Demo 今天打算写一个关于EF的CodeFirs的一个小Demo.先略说一个EF的三种与数据库,怎么说,叫映射么,好吧,那就这么叫吧,就是一个是ModelFirst就 ...

  6. 最短路径问题&sol;Spfa

    题目链接 题目描述 给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线, 则输出花费最少的. 最后一行是两个数 s,t;起 ...

  7. Mysql 锁基础

    本文同时发表在https://github.com/zhangyachen/zhangyachen.github.io/issues/53 lock与latch 在数据库中,lock与latch都可以 ...

  8. d4d&num;9 玩Docker只要浏览器就够了,PWD是个神奇的网站

    本文是d4d系列的第9篇,在这一篇中给大家介绍一个学习Docker最为快捷高效的方式,你不需要自己搭建环境,也不用担心把自己的开发环境搞乱,你需要的只是一个浏览器,就可以立即开始学习Docker的常用 ...

  9. navicat为mysql建立索引

    索引的目的是大大提高查询效率,还有读写效率. kettle向sql里面插入,更新时,也要建立索引,可以大大提升处理时间. 但是建立索引报错:Specified key was too long; ma ...

  10. 拖拽 &OpenCurlyQuote;vue-grid-layout’ 插件了解下

    我接触到vue-grid-layout是通过我们公司的项目,感觉还是比较简单上手的,大概看了有1个小时吧,我是个行动派,就是觉得实践出真知,但是记性也不太好,有时候自己踩过的坑会忘记,会改但是会忘记原 ...