- Bem 是块(block)、元素(element)、修饰符(modifier)的简写,由 Yandex 团队提出的一种前端 CSS 命名方法论。
- 中划线 :仅作为连字符使用,表示某个块或者某个子元素的多单词之间的连接记号。
__ 双下划线:双下划线用来连接块和块的子元素
_ 单下划线:单下划线用来描述一个块或者块的子元素的一种状态
1.1 BEM 命名模式
BEM 命名约定的模式是:
.block {}
.block__element {}
.block--modifier {}
-
每一个块(block)名应该有一个命名空间(前缀)
block
代表了更高级别的抽象或组件。block__element
代表 .block 的后代,用于形成一个完整的 .block 的整体。block--modifier
代表 .block 的不同状态或不同版本。 使用两个连字符和下划线而不是一个,是为了让你自己的块可以用单个连字符来界定。如:
.sub-block__element {}
.sub-block--modifier {}
1.2 BEM解决的问题
css的样式应用是全局性的,没有作用域可言。考虑以下场景
场景一:开发一个弹窗组件,新需求新页面,该页面一打开这个弹窗组件,页面中样式都变样了,弹窗组件和该页面的样式相互覆盖,
场景二:承接上文,由于页面和弹窗样式冲突了,所以把页面的冲突样式的选择器加上一些结构逻辑,比如子选择器、标签选择器,借此让选择器独一无二。一个元素对应多套样式,遍布整个样式文件...
BEM解决这一问题的思路在于,由于项目开发中,每个组件都是唯一无二的,其名字也是独一无二的,组件内部元素的名字都加上组件名,并用元素的名字作为选择器,自然组件内的样式就不会与组件外的样式冲突了。
这是通过组件名的唯一性来保证选择器的唯一性,从而保证样式不会污染到组件外。
这也可以看作是一种“硬性约束”,因为一般来说,我们的组件会放置在同一目录下,那么操作系统中,同一目录下文件名必须唯一,这一点也就确保了组件之间不会冲突。
BEM的命名规矩很容易记:block-name__element-name--modifier-name,也就是模块名 + 元素名 + 修饰器名。
一般来说,根据组件目录名来作为组件名字:
比如分页组件:
/app/components/page-btn/
那么该组件模块就名为page-btn,组件内部的元素命名都必须加上模块名
1.3BEM命名好长
BEM的命名中包含了模块名,长长的命名会让HTML标签会显得臃肿。
其实每个使用BEM的开发团队多多少少会改变其命名规范,比如Instagram团队使用的驼峰式:
.blockName-elementName--modifierName { /* ... */ }
还有单下划线:
.block-name_element-name--modifierName { /* ... */ }
还有修饰器名用单横线连接:
.blockName__elementName-modifierName { /* ... */ }
其实这些对缩短命名没有多大的帮助,但我们也无需担心文件体积的问题,由于服务端有gzip压缩,BEM命名相同的部分多,压缩下来的体积不会太大。另外现在都用IDE来编写代码了,有自动提示功能,也无须担心重复的输入过长的名字。
因为命名长,我们是不是可以用子代选择器来代替BEM命名?这样至少在HTML编写时,让HTML标签看起来美观一点。
BEM禁止使用子代选择器,以上是原因之一。子代选择器不好的地方还在于,如果层次关系过长,逻辑不清晰,非常不利于维护。为了懒得命名或者追求所谓的“精简代码”,写出下面这种选择器:
.page-btn button:first-child {} .page-btn ul li a {} /* ... */ /* 维护代码,新增需求 */ .page-btn .prev {}
1.4 BEM配置
参考链接: juejin.cn/post/684490…