摘要

当你在编写css代码的时候,是否遇到这样的困扰: 不知道取什么class名? 修改某个组件的样式,担心影响了其他组件? 编写的组件样式如何复用?为了解决这些问题,聪明的程序猿发明了BEM命名法。

BEM命名法,是对css命名的一种规范,将页面模块化,隔离样式,提高代码的复用性,减少后期的维护成本。BEM的意思就是Block(块)、Element(元素)、modifier(修饰符),通过双下划线__或者双中划--链接。

BEM通常用于框架开发中,比如微信WEUI、饿了么element-ui、有赞vant等。笔者也是通过阅读这些优秀框架的源码,学习到了这一套css命名大法,从此走上人生巅峰,赢取白富美。

1. 为什么需要BEM命名法

样式隔离, 避免css样式污染

css样式污染的根本原因,是因为css没有作用域。BEM通过特殊的命名方式,给css创造一个“作用域”,就能有效避免css样式全局污染。例如,给输入框命名

# 普通
.base input {}# BEM命名法
.base-input__inner {}

普通的命名法, 会作用于所有class='base' 的后代元素。 本来你只想给当前元素加样式,结果不小心影响了其他元素,这就是样式污染。
BEM命名法,只会作用于class='base-input__inner'的元素, 达到样式隔离。 不会影响其他元素。
有人会说css-module, 也能实现css“作用域”,而且作用域更唯一,我为什么要用BEM ? 客官,别急,且听我慢慢道来。

代码更易覆盖

假如,客官你正在开发一个通用的输入框组件, 用了css-module。打包后是这个样子

.base-input-sdFh3sxLwo5uer {}

另一位客官,用了你的输入框组件,但是觉得样式不好看,想修改样式。试了半天,发现,根本无法用css精确选择你的组件,因为.base-input后面的hash值是动态的。于是,这位客官,捶胸顿足,发誓再也不用你的组件了。

代码更易读

还是刚刚的输入框组件,base-input__nner, 不需要我解释,客官一眼就能看出: base代表基础组件,input代表输入框组件, inner是组件中的某一块。
~哇~,客官你真是太聪明了!

2. 什么是BEM命名法

BEM其实是块(block)、元素(element)、修饰符(modifier)的缩写,利用不同的块,功能以及样式来给元素命名。这三个部分使用__--连接(这里用两个而不是一个是为了留下用于块的命名)。命名约定的模式如下:

.block{}
.block__element{}
.block--modifier{}

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

常用规范

  1. block element modifier包含多个单词时, 用一个中划线-链接,例如
  2. el-dropdown-menu el-button
  3. blockelement用双下划线__链接, 例如
  4. 表单项 form__item
  5. 导航项 menu__item
  6. elementmodifier用双中划线--链接, 如表示按钮的不同状态,例如
  7. 默认:el-button--default
  8. 成功:el-button--success
  9. 用js控制样式时,css命名用is-开头,例如is-success、is-failed、is-disabled

常用的元素名

  • 表单元素 form form-item input select radio checkbox switch rate datePicker
  • 导航元素 nav subnav menu tab
  • 提示 alert message messageBox notification
  • 数据展示 table process tree pagiantion
  • 其他 button icon

3. 如何用好BEM命名法

页面命名

page-开头, page表示这是一个页面, 而不是组件。 给页面命名时,BEM可以搭配css-module一起使用。既能保证打包后选择器的唯一,又容易调试。例如

# 编译前
.page-index {}
.page-zufang {}# 编译后
.page-index-70yGFBg1eKjbSIwN {}
.page-zufang-mFTy62A1t83zjDbh {}

使用css-module, 打包后的clss名是可以修改的 参考

# 让打包后的文件更容易识别
{test: /.css$/,use: [{loader: 'css-loader',options: {modules: true,localIdentName: '[local]--[hash:base64:5]'}}]
}

页面中的选择器,都嵌套在页面根选择器内(.page-xxx), 保证所有样式, 只作用于当前页面。例如

<!- 页面命名 page-home ->
<div class="page-home"><div class="the-form"><div class="the-form-item"><div class="the-input"></div></div></div><div class="the-table"><div class="the-table-content"></div></div>
</div>.page-home {.the-form {}.the-form-item {}.the-input {}.the-table {}.the-table-content {}
}

公共组件命名

base-开头, base表示公共组件。

<div class="base-input"><input class="base-input__inner"/>
</div># 选择器避免嵌套,降低选择器权重
.base-input {}
.base-input__inner {}

公共组件的每一个class名,带上组件的作用域前缀,如base-input__inner的作用域前缀是base-input

选择器不宜嵌套, 让选择器的权重尽可能低。原因如下: base-input__inner已经具有有作用域了,无需再嵌套。 由于组件选择器权重较低,在组件外修改组件样式时,覆盖样式非常方便。

局部组件命名

the-开头, the表示某一特定的组件。

<div class="the-header"><div class="the-header__title" /><div class="the-header__desc">
</div># 选择器避免嵌套,降低选择器权重
.the-header {}
.the-header__title {}
.the-header__desc {}

局部组件的每一个class名,带上组件的作用域前缀,如the-header__title的作用域前缀是the-header

局部组件,也不宜嵌套, 降低选择器权重。

局部组件也可以搭配css-module一起用,因为局部组件只给少数特定页面使用,修改样式,可以在组件内部直接修改。

4. 其他注意事项

命名语义化

怎样衡量你的命名是语义化的?让一个人新人,来看一下你的代码,不需要解释,就能知道这个类的作用,就比较语义化.

通常,可以根据模块的功能而命名,如页面头部header、导航栏nav、主体main、侧边栏sidebar、底部footer等,这样整个页面看起来就比较清晰了,维护起来也比较方便。

# bad
.fl { ... }
.fr { ... }# good
# 左浮动
.is-float-left { ... }
# 右浮动
.is-float-right { ... }

上面的代码, fl、fr之类的命名,表达意思不够清晰,要知道具体的含义,还得去看代码。 而is-float-left, 就表达得非常清晰。

使用 class(类) 选择器, 避免使用 id、标签、伪类 选择器

标签、伪类 等选择器范围太广,不具有“作用域”的作用,会污染全局样式。例如,下面的代码中,.the-header a 选择器会选中the-header所有后代元素<a></a>

<div class="the-header"><a></a>
</div>
# bad
.the-header a { ... }

覆盖第三方组件样式时,重新起一个class名

使用原来的class名修改样式,可能会不小心影响了后代组件的样式。为了消除这个隐患,可以重新起一个class名,只作用于当前组件。例如修改ant-design的输入框组件样式

<div className="the-form"><Input className="the-input">
</div># bad 会影响the-form 后代的所有输入框
.the-form .ant-input {}# good 只会只用于className='the-input'的输入框
.the-form .the-input{}

总结

  • 为什么需要BEM命名法
  • 什么是BEM命名法
  • 如何用好BEM命名法
  • 其他注意事项

bem什么意思_BEM命名法相关推荐

  1. 驼峰命名法模态对话框

    模态对话框 window.showModalDialog("url","向目标对话框传的值","窗口特征参数") 打开模态对话框 模态对话框 ...

  2. c#命名法 【转】

    一.匈牙利命名法:广泛应用于象Microsoft Windows这样的环境中. Windows 编程中用到的变量(还包括宏)的命名规则匈牙利命名法,这种命名技术是由一位能干的 Microsoft 程序 ...

  3. 骆驼命名法,帕斯卡命名法和匈牙利命名法(转)

    一.匈牙利命名法:广泛应用于象Microsoft Windows这样的环境中.       Windows 编程中用到的变量(还包括宏)的命名规则匈牙利命名法,这种命名技术是由一位能干的 Micros ...

  4. 机房合作--驼峰命名法

    其实之前一直都是只听说过驼峰命名法,今天就详细的了解下驼峰命名法: 驼峰式命名法(Camel-Case)是电脑程序编写时的一套命名规则. 小驼峰法 变量一般用小驼峰法标识.驼峰法的意思是:除第一个单词 ...

  5. C语言中的关键字,变量的定义,变量的命名规则,交换两个变量的值,驼峰命名法【 C语言变量名命名法则】

    C语言结构 C语言中的关键字 变量 变量的定义 变量的命名规则 交换两个变量的值 驼峰命名法 C语言结构 上图中我们可以看到最外层是程序,内部是所有的构成,我们从最里面开始说明. 当我们用计算机语言来 ...

  6. 【转】匈牙利命名法(Hungarian Notation)

    http://www.hudong.com/wiki/%E5%8C%88%E7%89%99%E5%88%A9%E5%91%BD%E5%90%8D%E6%B3%95 匈牙利命名法 匈牙利命名法是一种编程 ...

  7. 三种编程命名规则:驼峰命名法 (壹)

    驼峰命令法(Camel): 骆驼式命名法(Camel-Case)又称驼峰式命名法,是电脑程式编写时的一套命名规则(惯例).正如它的名称CamelCase所表示的那样,是指混合使用大小写字母来构成变量和 ...

  8. 把骆驼命名法的变量,变为大写字母变小写且之前加下划线

    /** * 把骆驼命名法的变量,变为大写字母变小写且之前加下划线 * * @param str * @return */ public static String toUnderline(String ...

  9. ABAP开发环境终于支持以驼峰命名法自动格式化ABAP变量名了

    Jerry进入SAP成都研究院前,一直是用C/C++开发,所以刚接触ABAP,对于她在某些语法环境下大小写敏感,某些环境下不敏感的特性很不适应.那时候Jerry深深地怀念之前在C/C++编程时遵循的驼 ...

最新文章

  1. linux ext4增加大小,如何修改 ext4 文件系统的大小
  2. LeetCode实战:字符串相乘
  3. pyspark-mongo-input-output
  4. 41)子类和父类的内存关系
  5. list 置顶元素_java集合指定元素排序:最前,按照提供的顺序排序?求算法
  6. 排查 Linux 系统故障,看这一篇足够了。
  7. 字节跳动面试流程和考点都在这儿
  8. Leecode刷题热题HOT100(14)——最长公共前缀
  9. js数组获取index_通过事例重温一下常见的 JS 中 15 种数组操作(备忘清单)
  10. win7 ASP.NET 2.0 部署
  11. 如何才能更好发挥WinRunner,实现真正的自动化测试
  12. linux mint 下安装 wwscan
  13. 索爱小蜜蜂扩音器怎么样啊~
  14. Mysql的explain,你真的会用吗?
  15. 毕业设计So Easy:JSP+layui+MySQL实现Web端图书管理系统
  16. leetcode 5473. 灯泡开关 IV medium (智力题,O(n)思路详解)
  17. mac下idea选中多个相同内容的快捷键
  18. MATLAB S-function(教程分享) 报错 flag = 3(output), at time 0.0. 输入参数的数目不足。
  19. 理想职业是计算机的英语作文,我的理想职业大学英语作文
  20. LPC2124单片机的基础操作——GPIO、外部中断、定时器和串口

热门文章

  1. 前端学习(1749):前端调试值之如何查看js和css源码
  2. oracle之高级子查询1
  3. 前端学习(1423):ajax错误处理
  4. 前端学习(1398):多人管理18项目重定向
  5. 前端学习(1383):多人管理项目3
  6. mybatis学习(10): sql server身份验证和windows身份验证
  7. java学习(178):终篇?静态代理?动态代理?
  8. 玩转oracle 11g(12):卸载
  9. 单实例数据库和多实例数据库
  10. CSS之media Query