css class命名与作用域化

747 阅读6分钟

本篇整理的由来?

由于项目是多人开发的并有多人接手过,导致项目里面没有统一的css命名的规范,从而短横线,下划线,驼峰式的class命名混杂。作为一个没有自己原则的小白就迷失了方向,故从各个大佬的文章处搬砖以及自己实践整理了这篇文章。从此心里有了几点b数

class命名的困难

首先class和id是有区别的,id的设计初衷是唯一,只要保证唯一就好了,然而class的设计是要重复利用的,样式是可以覆盖的,而且是先按照选择器权重,再根据先后定义顺序。所以很可能你花了十分钟设计定义的class名,人家分分钟就把你干掉了

所以class的命名的难在于既要重复利用,又要避免样式的冲突。重复利用当然就是class名越简单越好,而要避免样式冲突就需要class名更具体,可以采用BEM命名方法。由于现在前端项目的工程化,css module也是一个不错的选择

css class命名的发展

主要分为4个阶段:

  • 混沌阶段,没有规则就是最好的规则

  • 原子类阶段,聚集神龙现身手,一个样式由很多单一的小样式组合而成

  • 模块阶段(SMACSS),以职能划分,添加前缀

  • BEM阶段,规则有序

混沌阶段:就是想怎么写就怎么写,写到哪里是哪里。看class去猜意思很可能就是错误的,如.red{color:red;font-size:14px;},明明说好的红色,却顺带定义了个字体大小

**原子类阶段:**Atomic CSS,即「原子 CSS」

也是面对属性命名,完全使用拼凑class名,这样会导致一个元素上面有很多class,会使HTML繁杂,而且如果这个原子命名不够原子并在很多地方使用了,一旦需求有所改变,那将是灾难性的

模块阶段:Scalable and Modular Architecture for CSS,即「CSS 的可扩展模块化架构」

是按照职能去划分,分为以下5种

  • Base: 基础标签的默认样式 (html, body, h1, ul 等),一般是重置

  • Layout: 大块的布局,可以 id 作为选择器

  • Module: 可复用的组件模块

  • State: 特定状态下的样式 (hidden 或 expanded, active/inactive)

  • Theme: 整站的一个主题

对应的命名方法:

  • Base: 无需命名,直接用标签作为选择器

  • Layout: l-layout- 前缀

  • State: is- 前缀,如 .is-active.is-hidden

  • Module: 可以不加前缀,也可以对相关的 module 加特定的前缀来方便组织

BEM阶段:B__E--M   

特点:

  •   组件化/模块化的开发思路

  • 书写方式解耦化,不会造成命名空间的污染,如:.xxx ul li 写法带来的潜在嵌套风险

  • 命名方式化扁平,避免样式层级过多而导致的解析效率降低,渲染开销变大。

  • 组件结构独立化,减少样式冲突,可以将已开完成的组件快速应用到新项目中

  • 有着较好的维护性、易读性、灵活性。

B: block  —— 区块名

  • 块名称之间用'-'短横线连接,
  • 块可以放置在页面上的任何位置,也可以互相嵌套

E: element —— 元素名

 一个元素始终是块的一部分,而不是另一个元素,因此元素名称不可定义为 block__elem1__elem2 的层次结构,要始终block_elem, 当然有时候也要具体情况具体分析,可以把元素单独脱离成块更有意义

M: modifiers(修饰符)—— 状态名

修饰符,一个block或者element上的flag,体现了外观或者行为的变化

修饰符是添加到块/元素DOM节点的额外类名。仅将修饰符类添加到它们修改的块/元素,并保留原始类名。是添加不是替换

当嵌套的比较深的时候要具体情况具体分析,必要时,可以把内部的element作为一个block,再进行新的嵌套。

当block-el2和block-el3,block-el4联系比较紧密的时候,就是如果3,和4受2控制,比如block__elem2中是flex布局子元素elem3, elem4,那可以把elem2单独出来作为一个块

BEM 加强了 HTML 的语义化,令代码更易读易维护。 由于命名规则与组件化的工程架构契合度较高,使得它成为目前比较流行的类命名方式。 

但同时劣势也非常明显,

  • 比较复杂,代码冗长,通常会导致自己都记不住自己取的class名,然后只能对着拷贝。
  • 复用性不高,并且要减小样式表大小只能再度跟组件联手,利用组件按需加载来减少首屏渲染的样式表大小

总结:

(1)不要用id来控制样式,因为它的权重太高,用id来写css就没有了复用性

(1)重置浏览器默认样式的reset.css

  (2)  用原子类(面向属性命名)的通用样式common.css

   (3) js操作的class名可以加上js-前缀或者使用驼峰,并且禁止使用js操作的class名去写样式

(4) 页面元素的短横线class名,特殊的可以用双短横线--,最外面的块的class名加上页面哈希值作为前缀,防止冲突

(5)不同的页面的样式写在不同的class文件里面,易于查找

css module

css modules是一种流行的模块化和组合CSS的系统,vue-loader提供了与css modules的集成,作为scope CSS的替代方案

<style scoped>
    .list-header:hover {
      background: orange;
    }
</style>

这个可选 scoped 属性会自动添加一个唯一的属性 (比如 data-v-12b2y23) 为组件内 CSS 指定作用域,编译的时候 .list-header:hover 会被编译成类似 .list-header[data-v-12b2y23]:hover

而CSS modules则做的更彻底,它不是添加属性,而是直接改变类名

css module的配置

要使用css module需要在webpack设置,只需要开通css-loader的module功能,同时可以设定class的名称

此时你新建一个css文件,往里面正常写样式就可以了,然后在js里面引入使用就可以了

css module的使用

  • 全局变量&局部变量

    :global:样式编译后不变,属于全局变量 :local:样式编译之后做localIndentName处理 如果不写前缀的话默认处理为:local

  • composes 组合class

很多时候我们都需要样式复用,在 CSS Modules 中,一个选择器可以继承另一个选择器的规则,这称为composes 组合。

  • css和js变量共享

使用:export关键字就可以进行css和js变量共享了

react里面使用css module

在用create-react-app脚手架生成的项目默认支持css module,它的webpack就已经设置好了,就是需要以.module.css或者.module.sass或者.module.scss后缀名命名需要模块化的css样式文件

四、参考