CSS命名方法整理

引子

周会上有同学提出我们现在定义的css不够优雅,过于原子化的class会在html中出现大量的class,造成HTML臃肿。


CSS命名方法:

css具有较大的随意性,很多都是依赖于框架的命名,没有一个统一的规范,单纯css本身命名比较主流的:

  • OOCSS
  • BEM
  • ACSS(Atomic CSS)

一、OOCSS(面向对象的CSS)

社区内最早提出的一种方法,也可以说是模块化CSS的起源,由NicoleSullivan 于 2009 年提出,这基于她在雅虎的工作。;面向对象对于后端开发人员可能较为熟悉,那么在CSS中的面向对象是什么?

CSS中的对象是一个可复用的样式规则,不是框架,单纯是一种写法

<style>
.btn {
    padding:  ;
    background-color: ;
    color: ;
}
</style>
<button class="btn">按钮</button>

在例子中我们定义了一个 btn 的css class,所以以后在页面中在使用按钮,直接用 btn 这个类就可以了。

OOCSS包含了两个原则:容器与结构分离、内容与样式分离;

容器与结构分离

通常在我们写CSS的时候,我们通常会根据Html元素的位置来规定样式,例如:

<div class="nav">
    <ul>
        <li>列表1</li>
        <li>列表2</li>
        <li>列表3</li>
    </ul>
</div>

<style>
.nav ul li {...}
</style>

而在OOCSS认为,我们的样式不应该根据元素的位置来判断对象的样式。

而是应该给元素定义自己的样式,如:

<div class="nav">
    <ul class="list">
        <li class="list-item">列表1</li>
        <li class="list-item">列表2</li>
        <li class="list-item">列表3</li>
    </ul>
</div>

<style>
.list {...}
.list-item {...}
</style>

也就是说,在网页中的任何位置使用 list ,我都不需要考虑 list 的上下文是什么,不论什么情况下 list 的样式都不应该改变。

内容与样式分离

现在我们就遇到了新问题,在之前我们定义了一个 btn 对象,现在我想要再网页中加入一个红色的按钮怎么办?

OOCSS提出了他的核心原则之一:内容与样式分离,他将对象设置为基本的样式,而如果这个对象存在多种多样的样式,我们通过添加皮肤的方式给他添加样式。

<style>
.btn{
   padding: 4px 8px;
   background-color: #bbb;
   color: #fff;
}

.red{
   background-color: red;
}

</style>
<button class="btn red">按钮</button>

这样我们要的红色按钮就出炉了,你们想要的绿色、蓝色等等等等爱要什么要什么…

OOCSS命名规则: 使用类名来扩展基础对象、坚持语义化的命名方式

使用类名来扩展基础对象

那么在这个例子中,我们可以看到我们使用了一个红色的按钮,但是我们会发现一个问题,如果当我们写了一个label的时候我们想让他的字体是红色的,我们如果不注意,样式很有可能会冲突。

<button class="btn red">label按钮</button>
<label class="label red">我是红色的label</label>

在OOCSS中,提倡将对象的皮肤使用其基础类名来进行拓展。

{...}
.btn-red {...}
.label {...}
.label-red {...}

这样我们一眼就可以看出,我们的扩展样式是对应哪个对象的。也减少了样式的冲突。

坚持语义化的命名方式

OOCSS提倡使用语义化的命名方式,这样有什么好处呢?我们可以根据名称给皮肤定义使用场景,在特定场景使用特定的皮肤,这样就不需要担心在网站中胡乱使用颜色了。

{...}
.btn-edit{  background-color: blue;}
.btn-delete{  background-color: red;}

很多组件库都使用这种命名方法,如bootstrap;这种方法就是让你的CSS代码更灵活、更具有可复用性、可维护行及可扩展性。


二、BEM(Block-Element-Modifier)

BEM代表块(Block),元素(Element),修饰符(Modifier), BEM将网页中的元素分为块、元素、修饰符,由 Yandex团队提出的一种前端命名方法论。

  • BEM是一种命名方法,能够帮助你在前端开发中实现可复用的组件和代码共享。
  • BEM是一个严格约定的命名规范,通过这种规范,来解决编写CSS是所遇到的问题。
/* 书写规范 */

.block {...} /* 块 块名*/

.block__element {...} /* 元素 块名 + __ + 元素名 */

.block--modifier {...} /* 修饰符 块名 + -- + 元素名 */

* .block 块:代表了更高级别的抽象或组件

* .block__element 元素:代表 .block 的后代,用于形成一个完整的.block的整体

* .block--modifier 修饰符:代表 .block 的不同状态或不同版本

块(Block)

我们可以将块理解为web应用中的组件或者模块。

特点:

  1. 嵌套式的构造

Block 可以被嵌套到任何其他 block 里面去。例如,一个头部 header 可以包含一个 logo 、一个搜索表单 form 和一个登录 login 。

  1. 随意放置

Block 可以在一个页面内任意移动,也可以在页面之间或项目之间移动。Block 作为独立的实体来实现,这使得在页面上改变 block 的位置 并确保其功能和外观一切正常 成为可能。

  1. 可复用

一个界面可以包含同一个 block 的几个实例。

元素(Element)

大部分组件都不是由多层HTML嵌套组成的,那么元素就是就是这个组件内部的各级元素。

这里需要注意的是,不论在HTML中一个块的结构是什么,在BEM规则中中,块下的元素全部属于块。

<div class="nav">
    <ul class="list">
        <li class="list-item">列表1 <i class="list-icon"></i> </li>
        <li class="list-item">列表2 <i class="list-icon"></i></li>
        <li class="list-item">列表3 <i class="list-icon"></i></li>
    </ul>
</div>
list-item 和 list-icon 都属于块 list 。

修饰符(Modifier)

修饰符与在OOCSS中的皮肤比较类似,属于组件在不同状态或组件的不同版本。

  • 一个块必须有一个“名字”(一个CSS类)才能被CSS规则所使用 带来的问题:
  • 如何给 modifier 下的 element 定义规则
  • BEM 导致 CSS 规则重用性降低

BEM解决的问题

  • CSS样式全局性造成的样式冲突问题
  • 多人协作的命名问题
  • 解决层叠问题,使CSS的优先级保持相对扁平
  • CSS的模块化,有一定的复用能力

BEM面临的问题:

  • 如何给 modifier 下的 element 定义规则
  • BEM 导致 CSS 规则重用性降低
  • 不好看

三、Atomic CSS(原子化CSS)

ACSS,由雅虎公司内部提出,并应用于雅虎官网,将重用性运用到了极端

Atomic Design(原子化思想)

在2013年网页设计师Brad Frost从化学中受到启发:原子(Atoms)结合在一起,形成分子(Molecures),进一步结合形成的生物体(Organisms)

Brad将这个概念应用在界面设计,我们的界面就是由一些基本的元素组成的。Josh Duck的“HTML元素周期表” 完美阐述了我们所有的网站、APP、企业内部网、hoobadyboops等等是如何由相同的HTML元素组成的。

  • Atoms(原子):为网页构成的基本元素(标签、按钮、颜色、字体)。
  • Molecules(分子):由原子构成的简单UI组件(搜索框)。
  • Organisms(组织):由原子及分子组成的相对复杂的UI模块(表单区域、工具栏等)。
  • Templates(模板):将以上元素进行排版,显示设计的底层内容结构
  • Pages(页面):将实际内容(图片、文章等)套件在特定模板,页面是模板的具体实例。

原子化CSS工具- Atomizer

理解了原子化的设计,那么为什么说原子化CSS就是将重用性进行到了极端。

让我们来举个例子,GitHub上面有一款开源的ACSS工具,叫做 Atomizer

我们使用它来看一下

<div class="Row">
    <div class="Fl(start) W(1/2) Bgc(#0280ae.5) H(90px)"></div>
    <div class="Fl(start) W(1/2) Bgc(#0280ae) H(90px)"></div>
</div>
<div class="D(tb) W(100%)" role="presentation">
    <div class="D(tbc) Bgc(#0280ae) H(90px)"></div>
    <div class="D(tbc) Bgc(#0280ae.5) H(90px)"></div>
</div>
   <div class="IbBox W(50%) Bgc(#0280ae.5) H(90px)"></div><!--

--><div class="IbBox W(50%) Bgc(#0280ae) H(90px)"></div>
<div class="D(f)">
    <div class="Flxg(1) Bgc(#0280ae) H(90px)"></div>
    <div class="Flxg(1) Bgc(#0280ae.5) H(90px)"></div>
</div>

看到这段代码,大家肯定会怀疑人生,这是什么鬼?!!

那么原子化的CSS到底是什么?

将CSS的代码最小化,每一个CSS的类里面只存在一条属性,而在使用时,用到这一条属性时,我们只需要在HTML的class中加入对应的CSS类就可以,最小化了CSS,但是造成了HTML的臃肿

以上代码只要遵循一定的规则,就可以通过工具自动生成的。

因为生成的代码过于丑陋,虽然是雅虎推行的,思想有被推广出来,但工具一直不温不火,被嘲讽的厉害!大部分接受ACSS的人宁愿自己定义手动实现自己的基础库,确保每个class应用单一规则,尽量复用

.mt20 {
  margin-top: 20px;
}
.fl {
  float: left;
}

原子化CSS工具- Tailwindcss

https://www.npmtrends.com/tailwindcss-vs-vue-vs-element-ui

ACSS优点:

  • 一致性:由于分解网站成单一元素,不论在哪一个页面,UI元素的互动性是相同的,例如颜色变化、字体的排序、以及回馈。不但让使用者经验相同,在视觉上更为和谐
  • 效率高:建立基础样式库后,一旦要更改某一个元素,可以马上施行、应用
  • HTML变大了,但CSS文件停止增长;如果开启gzip 的话,虽然会对HTML进行大幅压缩

ACSS缺点:

  • 臃肿
  • 看起来像内联样式没那么优雅

我们当前项目基本上是以ACSS思想为基础,多种命名方法混用;新项目可以考虑直接引入Tailwindcss,有VS的代码提示,对新人很友好~

引用文章:

OOCSS——概念篇

Atomic Design原子设计理念:构建科学规范的设计系统

如何评价Tailwindcss

什么是模块化 CSS?

CSS方法论