暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

在Vue的CSS中,我为何放弃scoped和module,而选择BEM命名法作为前端CSS规范

许咖啡Coffee 2022-05-26
197


在我们的项目实践中,因为缺乏统一的命名思想,经常会遇到样式污染的问题,大家都习惯性地一层一层包裹,为了简便,都写着一个单词的类名,某天突然发现样式被污染了,真是头大。

所以不论你是Vue的新手或者是老手,应该不多不少都会用过style的scoped属性来尝试避免样式污染的问题,用起来确实也挺方便。而Vue也支持使用CSS Modules,但是可能会用得少一点,甚至很多同学未曾接触过。

但是我们今天推荐的BEM命名法,是能让你感到惊艳的思想!


我们先来看看3种写法的优缺点:

Vue的CSS写法

scoped模式

test-scoped.vue文件代码
<template>
<div class="footer">
<button class="button">submit</button>
<button class="button buttonClose">close</button>
</div>
</template>

<!-- 使用 `scoped` attribute -->
<style scoped>
.footer {}

.button {
border: none;
border-radius: 2px;
}

.buttonClose {
background-color: red;
}
</style>

打包后的代码
<div data-v-0519b13b class="footer">
<button data-v-0519b13b class="button">submit</button>
<button data-v-0519b13b class="button buttonClose">close</button>
</div>

<style type="text/css">
.footer[data-v-0519b13b] {}
.button[data-v-0519b13b] {
border: none;
border-radius: 2px;
}
.buttonClose[data-v-0519b13b] {
background-color: red;
}
</style>

工作原理

scoped的原理其实是利用了css的属性选择器,编译的时候,打包器做了以下步骤:

  1. 为组件生成一个唯一hash值

  2. 为整个组件的所有DOM都添加一个data-v-hash的属性

  3. 为所有CSS类名增加属性选择

从而达到组件内的css与外部css隔离开来,

优点

易于把组件内的css捆绑在内部,从而不污染到其他地方

缺点
  1. 你会发现你不污染别人,但是会被别人污染,比如外部存在.footer的定义,那组件内尽管有被添加哈希属性,但是同样会受到影响

  2. 如果想影响子组件的css,需要额外添加不是css语法的deep属性进行穿透

  3. 如果父子组件都使用了scoped,那子组件的根元素也会有父组件的data-v-hash属性,有可能对子组件造成污染

  4. 当css和DOM都比较多的时候,大量的data-v-hash属性的DOM,会导致渲染速度下降,从而影响整个页面的性能

  5. 过于依赖,导致开发者养成非常不好的类名命名习惯

module模式

test-module.vue文件代码
<template>
<div :class="$style.footer">
<button :class="$style.button">submit</button>
<button :class="[$style.button, $style.buttonClose]">close</button>
</div>
</template>

<!-- 使用 CSS Modules -->
<style module>
.footer {}

.button {
border: none;
border-radius: 2px;
}

.buttonClose {
background-color: red;
}
</style>

打包后代码
<div class="test-module_footer_1fSjt">
<button class="test-module_button_3Yu2k">submit</button>
<button class="test-module_button_3Yu2k test-module_buttonClose_2YeyF">close</button>
</div>

<style type="text/css">
.test-module_footer_1fSjt {}
.test-module_button_3Yu2k {
border: none;
border-radius: 2px;
}
.test-module_buttonClose_2YeyF {
background-color: red;
}
</style>

工作原理

module的原理是以组件名和类名组合后,以某种算法为对应类名自动添加一个独一无二的随机字符串

优点
  1. 自动模块化类名,从而只要根据类名就能大概知道属于什么部分

  2. 类名几乎不可能重复,绝对隔绝,不会被外部污染,也不污染外部!

缺点
  1. 因为彻底与世隔绝,在父组件如果想修改一下组件样式,我们会发现无法精确定位,因为hash值在每次打包都动态生成的

  2. 随机生成的类名,无法进行复用

  3. 不符合常规的

BEM模式

test-bem.vue文件代码
<template>
<div class="footer">
<button class="footer__button">submit</button>
<button class="footer__button footer__button--close">close</button>
</div>
</template>

<!-- 使用 BEM 约定 -->
<style>
.footer {}

.footer__button {
border: none;
border-radius: 2px;
}

.footer__button--close {
background-color: red;
}
</style>

打包后的代码
<div class="footer">
<button class="footer__button">submit</button>
<button class="footer__button footer__button--close">close</button>
</div>

<style type="text/css">
.footer {}
.footer__button {
border: none;
border-radius: 2px;
}
.footer__button--close {
background-color: red;
}
</style>

工作原理

原生属性,不做任何编译,直接打包


为什么我会选择BEM

我们先简单理解一下什么是BEM

什么是BEM

BEM由块(Block)、元素(Element)、修饰符(Modifier)组成,写成类名是这样的:

<style type="text/css">
.block {}
.block--modifier {}
.block__element {}
.block__element--modifier {}
</style>

BEM命名约定

  • 多个单词之间用单个连接符 - 连接

  • 块与元素之间用双下划线 __ 连接 (.block__element)

  • 块或元素与修饰符之间用双连接符 -- 连接 (.block--modifier、.block__element--modifier)

  • 即:块__元素--修饰符

BEM的优点

  • 思路清晰:好多小伙伴可能在给css命名的时候会很头大,常常在没有指引下,可能都会直接用单个单词进行命名,容易对其他地方造成污染,有了BEM的思路,就很容易很规范也很自然地对类名进行命名


  • 命名清晰:从命名约定,我们可以看出,BEM希望我们把一个css类的用途明确写在类名里,属于哪个部分(块),作用是什么(元素),还有什么不同效果(修饰符)等。


  • 复用性高:修饰符代表同一个块或元素不同的状态,这种方式结合了OOCSS的思想,把整个网页拆分成不同的块,块里包含什么元素,这些块或元素可以重复利用,且还可以有其他不同的状态


  • 避免污染block的名称能直接反出这个块是属于什么模块的,不同模块名称不一样,从而很好地避免了污染的问题


  • 容易阅读理解:按照BEM思想写出来的类名,就算未了解过BEM的同学,在看到类名的时候,也可以很轻松地通过class类名,大致了解到这个元素的作用


  • 快速定位:因为名称的独特性,只要根据名称就能快速定位到组件文件并进行下一步操作

BEM的缺点

唯一的缺点就是类名长,随着模块的层级递增,block的名字会越来越长


总结

BEM思想真的很简洁,很容易掌握,但是又极其实用,刚接触BEM的时候,简直是如梦初醒,相见恨晚,为什么这么好的东西,一直没有人告诉我!!!而且在了解BEM后,才发现,原来各大前端UI框架(包含但不限于Element-UI,Vant-UI等),都是用BEM命名法。

虽然很多项目都在使用scoped,从而临时地避免了样式污染,但是过渡依赖后,基本上养成了大家都用那么些常用的单词做类名,哪天如果脱离了vue,没有scoped了,沿用这种习惯写出来的样式就会直接打起来。

所以与其依赖工具,还不如好好锻炼一种命名思维,养成一种好习惯,形成一个方法论,在没有任何工具的辅助下,都能避免样式污染的老难题!这不仅对项目好,也更是有利于我们的职业生涯!

因此,我很坚定选择了BEM思想作为团队内部的CSS命名规范!



本文首发于本人的知乎专栏,可以通过阅读原文查阅更多专栏文章哦~

关注我,下一篇文章,将会从实战的角度给大家讲解如何用好BEM命名法!


文章转载自许咖啡Coffee,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论