如何看待 CSS 中 BEM 的命名方式?

BEM的意思就是块(block)、元素(element)、修饰符(modifier),是由Yandex团队提出的一种CSS Class 命名方法。 类似于: .block{} .block__element{} .block--modifier{}A New Front-End Methodology: BEM
关注者
1057
被浏览
63052

23 个回答

再烂的东西,如果真的毫无价值,是会马上被历史所淹没的

每个领域都有沉淀下来对特定开发者在特定场景有用的东西
很赞同克军那句取其精华去其糟粕,何为精华,自己根据使用场景取舍

可能大多数同学看到那么多下划线中划线以及那么长我靠还有驼峰的名字,就会觉得混乱和不爽
不爽是一个很主观的词儿,他除了解决心理问题,没法解决生理问题

CSS这么多年并没有一个相对比较严谨的套路出来,宽松的写法导致团队成员写法各异,丢在页面都能跑起来,但混着做项目就不敢动或理不清别人写的代码
"这个CSS重写一遍比修改老文件快",这样的念头几乎所有人都曾有过.

我们团队用BEM快1年,下面我来谈谈一些心得

了解什么是 B.E.M

Block
!误区:这个block并非inline-block里的block,
而是将所有东西都划分为一个独立的模块,一个header是block,header里嵌套的搜索框是block,甚至一个icon一个logo也是block
block可以相互嵌套

Element
!误区:如果一个Element-son是另一个Element-father的子元素,
那么写法是 Block__Element-father__Element-son_Modifer,嵌套多了会很长么?
不是的!!!
一个Block下的所有Element无论相互层级如何,都要摊开扁平的属于Block
所以 BEM 最多只有 B+E+M 三级,不可能出现 B+E+E+..+E+M 超长class名,也要求E不能同名

Modifier
之前我们经常写的 .current .active 等表达状态


从Class中解读B.E.M

我们常说CSS的注释要写WHY,而不是写WHAT,看Class命名最好就知道是WHAT
BEM提出的一个概念是用连接符号来表达,它并不规定必须用什么连接符,但规定用不同连接符做团队内约定区分BEM 3类元素

例如我们组内约定
__双下划线代表B和E连接例如 menu__item
_单下划线代表B和M或E和M的连接 例如 menu_active 或 menu__item_active
-中划线同英语里做连字符例如 mod-menu 或 mod-menu__item 这里 B或E或M需要多个单词来描述,就使用中划线

打字会抽搐吧...
你听说过Emmet么?再不济Zen Coding有听说过吧?实在不行听说过安利也行啊
FYI docs.emmet.io/filters/b

拆分Block到文件


我们并没有用BEM推荐的拆分CSS到更多目录里,图片是拆目录的.因为用的是 Grunt+LESS
团队项目特色为N个相互独立的移动端项目,Block并不会很多,所以文件扁平化很直观,带来的效率也相对高,如图为其中某个项目的css部分
另外,写block的时候需要新建less文件,字母排序,是否重名都很清晰

按ctrl+f查找class定位和按快捷键打开文件名没啥大区别,更何况新版LESS还有source map

最后我们团队正在开发对应模块管理的工具,目标是向NPM一样玩,同Alice一样规划解决方案

代码复用

代码风格可能文档里说的也不是很详细,不如直接对着他们的页面按F12吧 beta.yandex.com/
BEM/OOCSS 风格对维护重用的class有极大帮助,适当的拆分block后组合,威力无穷

那个千年老栗子——如果我想将一个f30的类,改成f35怎么办?是挂羊头卖狗肉的直接将.f30{font-size:30px}改成.f30{font-size:35}吗?还是要进行全局搜索,改动所有的html的class名?
或者 Alice 里面的
.text-size30{font-size:30px;}
.text-size20{font-size:20px;}
.text-size10{font-size:10px;}

而我们采用的是类似 bootstrap 的方案
用程度来划分,而非具体数值,所以根本就不会存在.text-size30这么个类,那个写style上去有毛线区别.

在var.less里定义具体的数值

在 ui.less 里调用

BEM的任何一个block都可以到处用,这对模块并不多的手机项目非常有利.

关于hax大神吐槽的不用ID和后代选择器

ID
ID对于我和!important对于我一样,并不否认价值,但想不起来上一次用是啥时候了.
说到这里顺便提一下 z-index的问题,有多少同学写z-index的时候会写1000+?有做过整站z-index规划么? 同样的用 class 如果能规划好了,我是不倾向用id,也想不到有什么非用ID不可的情况,性能什么的,呵呵,测过,影响不大
特定场景例子:在腾讯,JS和CSS是分别2种团队的人在写,我们约定ID给JS,class给CSS和固定前缀的JS hook,不管是不是BEM,ID在我们这两种团队约定下也是不使用,并且也没带来啥问题

后代选择器
这个BEM写block的时候是不用,但block相互嵌套的时候是用的,
例如一个状态下需要变动多个表现,用后代选择器一次性处理
性能以及JS/CSS代码可维护性都有明显优势
节选自 yandex.st/search_island

Tag selector 是翻译成标签选择器么
BEM是不允许用标签选择器的,一开始难以接受...
.menu li 能搞定的事情需要每个 li 都写.menu-item

坏处
是 k 数增加么?gzip下真不是个问题,或者是写代码额外工作量?这难道不是动态生成的么?再不济编辑器也可以随便列编辑或复制当前行或代码提示啊

好处
就是避免 li 里的 li 受影响
举个例子,商品详情页是允许商家自定义标签的,那么商家展示区域标签的祖先元素一旦用标签选择器定义了样式,子子孙孙都要背负.

所以十分赞同在无法百分百确定不会嵌套同样标签的情况下不用标签选择器


团队最重要的是统一
有一次讨论连字符用中划线还是下划线的时候,谁也说服不了谁,
最后一个掌勺的拍板,大家统一用一个,而非同一个团队多种风格.
这对上下游合作,内部合作都会极大的降低沟通成本

之所以用 BEM(部分),也是因为没找到更好的类似规范,虽然有缺陷,但至少可以统一
讨论一个东西,我们很容易找出他的槽点,但是提出更好解决方案的同学少之又少,
从BEM中我们可以学习他优秀的方面纳为己用,
团队合作永远是统一高于一切


20160812 更新:
smashingmagazine.com/20
BEM除了是一种新的命令方式之外,我个人认为他还是提出了模块与模块,组件与组件,模块与组件之间的管理方式。如何通过一种命名方式更好的管理和维护他们。
仅除命名的方式出发,很多同学会接受不了,认为命名繁琐,增加了文件体积,另外编写样式,写选择器麻烦,从而增加了工作量。如果仅从这两方面来说他不好,或许有点过激。
从一种思想上来看,BEM还是有很多值得大家去思考的,特别是用于维护项目,或者跨团队的开发当中,他的好处会明显见长。
任何一样东西能生存,都有其自己的优势,当然万物有得就必有失。这是相互的,至于我们前端人员,或者一个团队如何取舍,还是需要从自已或团队力量出发,有利用之,无利就不用了
为什么?