Open AnnGreen1 opened 4 months ago
昨天在群里看到大家对CSS BEM和CSSmodule的讨论,激起了我的好奇心,我也想通过这篇文章向更多人科普一下CSS BEM / CSS Module / scoped 在代码中到底是个啥,他们究竟在做些什么。
方便起见,Scoped和CSS module的内容我主要使用vue作为示例,因为vue cli创建的工程是默认支持以上两种情况的。
首先我们需要了解这句话 ------ CSS的影响是全局的。
但是更多时候我们更喜欢他局部生效,所以就出现了上面的几种解决方案,下面是对此的详解。
更多详情参考:CSS BEM 书写规范
<style> .模块名-元素名--修饰符{} .moduleName-elementName--modify {} .paging-button--prev {} .paging-button--next {} </style>
如上所示,CSS BEM (Block - Element - Modify)其实是一种约定俗成的 模块-标签--修饰符 的 CSS 命名方式。
举例:在分页组件(/app/components/paging.vue)中,模块名就是paging,模块内的每一个元素的class命名都必须是模块名开头,上一页按钮对应的元素名或者内容(可以自己取一个合适的名字)为 button,最终他的class就为 paging-button--prev。
paging
button
paging-button--prev
优点:
缺点:
我们看到的scoped通常是如下使用的:
<template> <button class=”button” /> </template> <style scoped> .button { color: red; } </style>
最后的渲染实际是这样的:
<style> .button[data-v-f61kqi1] { color: red; } </style> <button class="button" data-v-f61kqi1></button>
scoped实际上是给每个标签加入了一个data属性,每个scoped里的样式渲染的时候,是根据这个标记的data属性渲染,从而实现的局部样式。
场景 参考文章:《Vue中的scope样式穿透(转载)》
但是在某些场景下,scoped是不够用的。
比如我们的页面嵌套了第三方的一个组件,我们在css上定位到组件需要修改的class为a,scoped规定我们是不能修改这个class的,这个时候就需要穿透scoped,这种情况可以使用 >>> 连接符(或者 /deep/ )实现。
>>>
/deep/
<style scoped> 外层 >>> 第三方组件 { 样式 } 例如, .container >>> .a { color: 'red' } </style>
如何在vue项目里开启 CSS Module,请移步官网:https://vue-loader.vuejs.org/zh/guide/css-modules.html#%E7%94%A8%E6%B3%95
参考文章:《[译] Vue: scoped 样式与 CSS Module 对比》 更多CSS Module技巧,请参考:《CSS Modules 用法教程》
我平时没有用过CSS Module,但是经过这一次的了解,我非常期待在项目中使用它,他的使用如下:
<style module> .button { color: red } </style>
乍一看,他在vue中的使用几乎和scoped没有差别,但他非常不同。
<style> .ComponentName__button__2Kxy { color: red; } </style>
$style
<template> <button :class="$style.button" /> </template>
以上生成如下代码: ```html <style> .ComponentName__button__2Kxy { color: red; } </style> <button class=”ComponentName__button__2Kxy”></button>
这样乍一看很麻烦,但厉害在这里,可以在 CSS 中定义你的色彩变量的同时将其导出,以供你的组件使用,从此不需要在组件里重复声明了!
<template> <div>{{ $style.primaryColor }}</div> <!-- #B4DC47 --> </template> <style module lang="scss"> $primary-color: #B4DC47; :export { primaryColor: $primary-color } </style>
CSS Modules 允许使用:global(.className)的语法,声明一个全局规则。凡是这样声明的class,都不会被编译成哈希字符串。
其他文章参考:使用了css modules怎么修改antd组件的默认样式,修改antd的样式
如果想修改全局的第三方样式:
:global{ .ant-modal-content{ background-color: transparent; } }
如果只想修改制定的第三方样式,那就给模块新增一个class,再修改:
<Modal className="tableBottomPop"></Modal> :global{ .tableBottomPop{ .ant-modal-content{ background-color: transparent; } } }
以上的三种都是针对CSS局部样式的实现方案,没有太多的孰是孰非,我们根据自己的使用场景进行挑选就好。
选定某一种方案,我们多记住他的"优缺点",使用好的尽量避免差的就很可以了,实际中可没那么多的大问题"吓人",总可以找到方法解决的。
作者:vivi_chen 链接:https://juejin.cn/post/6885587863720132615 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
昨天在群里看到大家对CSS BEM和CSSmodule的讨论,激起了我的好奇心,我也想通过这篇文章向更多人科普一下CSS BEM / CSS Module / scoped 在代码中到底是个啥,他们究竟在做些什么。
为什么会出现这么多名词
首先我们需要了解这句话 ------ CSS的影响是全局的。
但是更多时候我们更喜欢他局部生效,所以就出现了上面的几种解决方案,下面是对此的详解。
CSS BEM
如上所示,CSS BEM (Block - Element - Modify)其实是一种约定俗成的 模块-标签--修饰符 的 CSS 命名方式。
举例:在分页组件(/app/components/paging.vue)中,模块名就是
paging
,模块内的每一个元素的class命名都必须是模块名开头,上一页按钮对应的元素名或者内容(可以自己取一个合适的名字)为button
,最终他的class就为paging-button--prev
。优点:
缺点:
Scoped
我们看到的scoped通常是如下使用的:
最后的渲染实际是这样的:
scoped实际上是给每个标签加入了一个data属性,每个scoped里的样式渲染的时候,是根据这个标记的data属性渲染,从而实现的局部样式。
穿透scoped
但是在某些场景下,scoped是不够用的。
比如我们的页面嵌套了第三方的一个组件,我们在css上定位到组件需要修改的class为a,scoped规定我们是不能修改这个class的,这个时候就需要穿透scoped,这种情况可以使用
>>>
连接符(或者/deep/
)实现。优点:
缺点:
CSS Module
如何在vue项目里开启 CSS Module,请移步官网:https://vue-loader.vuejs.org/zh/guide/css-modules.html#%E7%94%A8%E6%B3%95
我平时没有用过CSS Module,但是经过这一次的了解,我非常期待在项目中使用它,他的使用如下:
乍一看,他在vue中的使用几乎和scoped没有差别,但他非常不同。
$style
来获取;这样乍一看很麻烦,但厉害在这里,可以在 CSS 中定义你的色彩变量的同时将其导出,以供你的组件使用,从此不需要在组件里重复声明了!
修改第三方组件
CSS Modules 允许使用:global(.className)的语法,声明一个全局规则。凡是这样声明的class,都不会被编译成哈希字符串。
如果想修改全局的第三方样式:
如果只想修改制定的第三方样式,那就给模块新增一个class,再修改:
优点:
缺点:
总结
以上的三种都是针对CSS局部样式的实现方案,没有太多的孰是孰非,我们根据自己的使用场景进行挑选就好。
选定某一种方案,我们多记住他的"优缺点",使用好的尽量避免差的就很可以了,实际中可没那么多的大问题"吓人",总可以找到方法解决的。
作者:vivi_chen 链接:https://juejin.cn/post/6885587863720132615 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。