学习
实践
活动
专区
工具
TVP
写文章

BEM、CSS Modules、CSS-in-JavaScript

相信大家在写样式的时候会遇到如下问题:

全局样式污染:CSS 的选择器是全局生效的,所以在 Class 名称比较简单时,容易引起全局选择器的冲突,导致样式污染。

命名混乱:因为怕全局样式污染,所以日常起 Class 名称时会采取某些方法来避免命名重复,但当项目由多人维护时,很容易导致命名风格不统一,难于管理。

样式重用困难:有时虽然知道项目上已有一些相似的样式,但因为怕互相影响,不敢重用。

代码冗余:由于样式重用困难等问题,会导致大量 CSS 代码冗余。

BEM(Block-Element-Modifier)

一套好的 CSS Class 命名方法,不仅能够增加代码的可读性,还能够增加项目的可维护性和易扩展性,所以,对于团队来说,遵守一套命名规范是很重要的,但是能始终严格遵守规范是一件很难的事。

BEM – meaning block, element, modifier – is a front-end naming methodology thought up by the guys at Yandex. It is a smart way of naming your CSS classes to give them more transparency and meaning to other developers. They are far more strict and informative, which makes the BEM naming convention ideal for teams of developers on larger projects that might last a while.

BEM 是由 Yandex 团队提出的一种巧妙的命名方法,通过这种命名方法写的 CSS Class 对其他开发者来说可读性非常强。另外,BEM 命名约定非常严格,能够包含非常多的信息,当一个团队开发一个大项目的时候,这种命名方法非常适用。

BEM 是 Block、Element、Modifier 的缩写,利用不同的区块,功能以及样式来给元素命名。这三个部分使用 与 连接(这里用两个而不是一个是为了留下用于块的命名)。命名约定如下:

.block {}

.block__element {}

.block--modifier {}

.block__element--modifier {}

BEM 的原则很简单:一个 Block 代表一个对象(一个人、一个登录表单、一个菜单);一个 Element 是一个块中作为特定功能的组件(一个帮助按钮、一个登录按钮、一个菜单项);一个 Modifier 是我们如何表示块或元素的不同变化(一个女人、一个带有隐藏标签的迷你登录框、 footer 中一个不同的菜单)。

一段没有使用 BEM 命名的代码:

这种写法使得 HTML 层级结构不够清晰,并且在写 CSS 代码的时候,必须依靠层级选择器来约束作用域,以避免跨组件的样式污染。

一段使用 BEM 命名的代码:

通过这种命名方式,HTML 层级结构一目了然,组件功能清晰明朗,而且不必使用过多的层级选择器,在一定程度上能够提高 CSS 的渲染速度。

BEM 为我们带来了什么好处?

代码结构更加清晰

通过这种命名方式,在阅读 HTML 代码的时候,能够快速掌握 DOM 结构,了解组件功能。

规范化

因为 BEM 的严格规范,我们没有太多选择,但在大多数的时候,这不失为一件好事,与其费尽心思想着怎么取一个语义化的 CSS Class,不如按照规范一步步来的省事。

利于团队协作

当后来人在你之前写的代码上增加新功能时,不需要过多担心样式冲突,只需要在新增加的 Block 或者 Element 中工作即可,更利于团队协作。

BEM 的槽点

命名过长问题

在 DOM 层级过深的情况下,会导致 CSS Class 冗长,难以阅读,所以使用 BEM 命名的层级一般不超过4层。

无法根治样式污染问题

在某些情况下,比如命名稍不注意导致重名,就可能会出现样式污染问题,使用第三方库的情况下也有可能会产生命名冲突,导致样式污染。

Docs here! : https://en.bem.info/methodology/quick-start/

Get BEM: http://getbem.com/naming/

CSS Modules

A CSS Module is a CSS file in which all class names and animation names are scoped locally by default.

CSS Modules 使用起来非常简单,下面以 React 中的使用作为例子,使用的是 css-loader 插件,代码如下:

将生成如下所示代码:

被编译成这个 hash 字串CSS Modules 使得 Class 在局部作用域内独一无二,不会对全局的样式造成污染。

Webpack配置如下:

CSS Modules 更多的用法可以去官网查看,此处不再赘述。

比起 BEM,CSS Modules 的优势在哪里?

作用域更加干净

再也不必担心样式污染问题,可以随意使用同名的 CSS Class,怎么舒服怎么来。

简化语法

比起 BEM 形如这种冗长的写法,CSS Modules 简化清晰了很多。

关于 CSS Modules 更多的好处,可以参考这篇文章CSS Modules 的优势: https://glenmaddern.com/articles/css-modules

CSS-in-JavaScript

顾名思义,JavaScript 里的 CSS,聪明的你肯定想到了 React,下面是 React 的一个例子:

表面上,React 的写法是 HTML、CSS、JavaScript 混合在一起。但是,实际上是用 JavaScript 在写 HTML 和 CSS。React 在 JavaScript 里面实现了对 HTML 和 CSS 的封装,通过封装去操作 HTML 和 CSS。也就是说,网页的结构和样式都通过 JavaScript 操作。

React 对 CSS 封装非常简单,就是沿用了 DOM 的 style 属性对象,由于对 CSS 的封装非常弱,衍生了一系列的第三方库,用来加强 React 对 CSS 的操作,它们统称为 CSS-in-JavaScript。目前市场上已经有至少50个 CSS-in-JavaScript 库,比较主流的是 styled-component、Radium。

这种模式的好处非常多:

组件的隔离性非常好,组件之间无耦合,只包含了自己需要用到的样式,不依赖外部,再也没有样式污染问题出现了,并且易于复用。

CSS-in-JavaScript 就是在组件内部使用 JavaScript 来对 CSS 进行了抽象,可以对其声明和加以维护,这样不仅降低了编写 CSS 样式带来的风险,也让开发变得更加轻松。

这种模式只生成页面需要用到的代码,缩减了最终包的大小,提升了性能。

命名混乱问题也得到了解决。

更加利于 CSS 的单元测试,增加了样式重构的安全性。

JavaScript 和 CSS 之间可以共享变量,写代码更 HAPPY 了!

CSS-in-JavaScript 的好处很多,也有一些不好的地方:

学习曲线比较陡,引入新的依赖。

新手难以将其应用在项目中,他们需要学习更多的东西。

挑战现有 JavaScript、CSS、HTML 分离标准(这个其实算不上是个不好的地方)。

在 Debug 的时候需要花更多的功夫才能找到对应的样式代码。

覆盖第三方插件样式时会有权重不够的问题。

Lint 工具对于 JavaScript 内部的 CSS 代码样式支持的还不够。

对前端框架存在依赖性,更适合于组件化的框架,如 React 等。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190111G0WTH200?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

关注

腾讯云开发者公众号
10元无门槛代金券
洞察腾讯核心技术
剖析业界实践案例
腾讯云开发者公众号二维码

扫码关注腾讯云开发者

领取腾讯云代金券