CSS设计模式

·  阅读 1189

前言

传统的CSS书写风格是随意命名,堆叠样式,造成了混乱不堪的结果,你是否遇到庞大复杂的项目里,CSS代码难以维护的情况,你是否想要除了能够还原实物原型,而且代码规则有序极易维护。

那么CSS设计模式就在实际应用中的拯救样式混乱,代码行数冗余的局面。这也是对一个项目设计CSS架构基础。

啥?CSS还有设计模式!

没错儿,CSS真的有设计模式。

本次分享主要从一些非常基础的代码案例梳理CSS设计模式的理论,相信大家看到每段代码都会发现这就是大家每个人日常使用的东西,可能有的人在用,但是没意识到这就是CSS的设计模式,这里呢就是将这些东西进行梳理总结。

重要的不是代码,重要的是思想。

设计模式:OOCSS

OOCSS是比较基础的设计模式,其他设计模式或多或少都有OOCSS的影子。那么什么是OOCSS呢?估计大家看到OO的时候就已经知道了,没错,就是是面向对象,那么面向对象和我们写CSS有半毛钱关系吗?当然有。

OO:面向对象

大家都很熟悉面向对象,我们简单看下下面这一段代码:

class Person {
    void study () {}
}

class Teacher extends Person {
    void study () {}
    void teach () {}
}

class Student extends Person {
    void study () {}
}
复制代码

有一个Person类,它有一些方法,Teacher和Student都继承Person,并且进行了一些修订和扩展。那么我们可以把Person类看成是别人写代码,在不改变别人源码的情况下,新增Teacher和Student对源码进行修订和扩展。这种写法是完全可以应用到CSS上面的。我们看下面一段代码场景:

<div class="menu"></div>
<div class="menu fix"></div>
<div class="menu"></div>

.menu {
   color: green;
   font-size: 14px;
}

.fix {
   color: red;
}
复制代码

场景:设计师只想让我们改变其中一个盒子的样式,其他的不变。

这时不能轻易改变menu,因为一旦改变就会影响不需要改变的地方。那么我们可以直接利用面向对象的思想,在后面单独添加一个类进行修订和扩展。这样一看我们平时在写的CSS,不就是面向对象吗?

当然,OOCSS是有具体的原则的。那么它有哪些原则且个原则的具体是什么呢?我们来看一下:

原则一:容器与内容分离

容器与内容分离顾名思义,直接看一个代码案例:

<div class="post"> 
  <p class="metadata">
    <a>Hello</a>
  </p>
</div>

<div class="comment"> 
  <p class="metadata">
    <a>Hello</a>
  </p>
</div>

// ---------code 1-----------
.post .metadata {
  // css code
}

// ---------code 2-----------
.post {}
.metadata {
  // css code
}

复制代码

场景:两个不同容器中的内容相同

先看样式的code 1,这样显然不好,容器和内容是嵌套依赖关系,并没有做到容器与内容分离。内容的样式无法复用。样式的code 2做到了容器与内容分离,内容在不同的容器中可以复用。

原则二:结构与皮肤分离

结构可以看做是一个基础对象,而皮肤可以看做是另外一个对象,也就是对象与对象要分离。基础对象不能改,不断的分离出皮肤对象达到对基础对象的修正和扩展。

<div class="menu fix"></div>

// 基础对象
.menu {
  color: green;
  font-size: 14px;
}
// 皮肤
.fix {
  color: red;
}
复制代码

OOCSS与Vue的关系

我们每天都在写OOCSS,Vue的组件就是OOCSS。我们下面一段代码:

// -------------定义组件-----------------
<template>
  <div class="menu"></div>
</template>

<script>
  export default {
    name: 'MateData'
  }
</script>

<style> 
// 基础对象
.menu {
   color: green;
   font-size: 14px;
}
</style>

// -----------使用组件-------------------

<template>
  <mate-data class="fix1"></mate-data>
  <mate-data class="fix2"></mate-data>
</template>

<style> 
// 皮肤
.fix1 {
   color: red;
}
.fix2 {
   font-size: 20px;
}
</style>
复制代码

OOCSS的应用
Grid栅格系统、布局组件等

设计模式:BEM

什么是BEM

BEM即块(Block)、元素(Element)、修饰符(Modifier) 是由Yandex(俄罗斯最著名的互联网企业)的开发团队提出的前端开发理论。BEM通过Block、Element、Modifier来描述页面(关键就是为了解决多人协作的命名问题)。 Block是页面中独立存在的区块,可以在不同场合下使用。每个页面都可以看做是多个Block组成。 Element是构成Block的元素,只有在对应Block内部才具有意义,是依赖于Block的存在。 Modifier是描述Block或Element的属性或状态。同一Block或Element可以有多个Modifier,Modifier不可以单独存在。 在命名时,Block作为起始开头,不同 Block 和 Element 用 _ 两个底线区隔开来,不同的 Modifier 则用 – 区隔。

进阶版的OOCSS BEM就是进阶版的OOCSS,我们看下图所示:

场景: 页面两个tab栏,整体布局相似,只有细节部分不同

那么使用BEM写样式时,就会定义一个块menu,下面包含元素menu_tab,完成整体布局,细微部分使用修饰符menu_tab-style1进行微调。代码如下:

<!-- BEM -->
<div class="menu menu-style1">
  <div class="menu_tab menu_tab-style1"></div>
  <div class="menu_tab menu_tab-style1"></div>
  <div class="menu_tab menu_tab-style1"></div>
  <div class="menu_tab menu_tab-style1"></div>
</div>

<div class="menu">
  <div class="menu_tab menu_tab-style2"></div>
  <div class="menu_tab menu_tab-style2"></div>
  <div class="menu_tab menu_tab-style2"></div>
  <div class="menu_tab menu_tab-style2"></div>
</div>
复制代码

通过上面代码可以看出BEM就是OOCSS。

对BEM感兴趣的话,可以访问BEM的官网: 

作用:
命名规范、让页面结构更清晰
另外关于命名规范使用的符号,团队内部是可以讨论修改的,不一定非要按照这种符号,BEM只是提供一个思想。

设计模式:SMACSS

SMACSS is a way to examine your design process and as a way to fit those rigid frameworks into a flexible thought process. (SMACSS通过一个灵活的思维过程来检查你的设计过程和方式是否符合你的架构,更像一种规范~)

核心思想:分类

SMACSS的核心就是分类,它主要要求分为五大类分别是:Base、Layout、Modules、State、Theme

  • Base是对浏览器默认样式的重置,常见的normalize.css就属于此。这里样式只会对标签元素本身做设定,不会出现任何 class 或id,但是可以有属性选择器或是伪类.

  • Layout对页面布局的一些功能,属于较高的一层,它可以作为层级较低的Module Rules元素的容器。左右分栏、栅格系统等都属于布局规范。SMACSS还约定命名使用l-/layout-前缀来标识布局的class。

  • Modules公共复用的小模块,模块是SMACSS最基本的思想,同时也是大部分CSS理论的基本,将样式模块化就能达到复用和可维护的目的,但是SMACSS提出了更具体的模块化方案。SMACSS中的模块具有自己的一个命名,隶属于模块下的类皆以该模块为前缀,例如:.menu .menu-title等。

  • State对不同的展示效果,例如显示、隐藏,与BEM抽取修饰类的方式的不同,SMACSS是抽取更高级别的样式类,得到更强的复用性,命名全都以is-前缀,如:is-hidden。

  • Theme对不同主题皮肤的维护,可以修改前面4个类别的样式,且应和前面4个类别分离开来(便于切换,也就是“换肤”)。命名规范需要添加theme-前缀。

最小适配深度原则

/* depth 1 */
.sidebar ul h3 {}

/* depth 2 */
.sub-title {}
复制代码

两段css的区别在于html和css的耦合度(这一点上和OOCSS的分离容器和内容的原则不谋而合)。可以想到,由于上面的样式规则使用了继承选择符,因此对于html的结构实际是有一定依赖的。如果html发生重构,就有可能不再具有这些样式。对应的,下面的样式规则只有一个选择符,因此不依赖于特定html结构,只要为元素添加class,就可以获得对应样式。

当然,继承选择符是有用的,它可以减少因相同命名引发的样式冲突(常发生于多人协作开发)。但是,我们不应过度使用,在不造成样式冲突的允许范围之内,尽可能使用短的、不限定html结构的选择符。这就是SMACSS的最小化适配深度的意义。

在项目中使用SMACSS时,每一个分类都是一个目录,但是在Vue中,Layout和Modules不需要单独维护目录,因为我们写的布局组件和模块组件就相当于这两个分类了。

如果想要对SMACSS更详细的了解可以访问:smacss-zh.vercel.app/preface.htm…

设计模式:ITCSS

这是由csswizardry提倡的一个 CSS 设计方法论,它可以让CSS更好的管理和维护。

使用ITCSS主要可以帮助我们以下几点:

  • Manages source order.

  • Filters explicitness.

  • Tames the cascade.

  • Sanitises inheritance.

大概意思就是:

  • 管理 CSS 代码的书写顺序。

  • 过滤器的明确性,是说分层来明确每层 CSS 的作用。

  • 控制好 CSS 的权重

  • 安全地使用继承

核心思想:分层

ITCSS的核心是分层,主要分为七层, 与SMACSS的分类相比更加精细,层次分的更细主要有:

下面就是ITCSS的架构模型:

从这个模型可以看出来,越往下就越具体,越局限于使用在某个具体的东西。另外它的下一层永远继承上一层的所有样式。

各个分层例子

Settings

全局变量,比如颜色,字体大小等等

$yellow: #FAAF00;
$yellow-bright: #FAF7F0;
复制代码

Tools

mixin,function 等等

@mixin sample-mixin () {
  ...
}
复制代码

到 Tools 为止,不会生成具体的 css

Generic

reset,normalize 等等

*,
*::before,
*::after {
  box-sizing: border-box;
}
复制代码

Base

type selector 比如 link, p 等等,只有这一层才使用 type selector

p {
  margin: 0
  line-height: 1.5;
}
复制代码

Objects

Cosmetic-free,不使用比如 color、border-color、background-color 之类的

使用这个 CSS 你在浏览器上面只可以看一片空白

主要用来做画面的 layout

.o-container {
  box-sizing: border-box;
  margin: 0 auto;
}
复制代码

Components

UI 组件

到这个部分,根据UI分析具体有哪些组件需要实现,可以分给多个人来同时实现

# button组件

.c-btn {
  display: flex;
  justify-content: center;
  align-items: center;
  ...

  &--primary {
    background-color: #ff5959;
    color: #fff;
  }

  &--large {
    font-size: 16px;
    padding: 16px 14px;
    ...
  }
}
复制代码

HTML 类似这样

<a class="c-btn c-btn--primary" href="#">sample</a>
<a class="c-btn c-btn--primary c-btn--large" href="#">sample</a>
复制代码

Trumps

放各种 helper

最主要的作用是用在不适合或者不容易放在 Component 的时候

比如 margin,很可能不应该放 Component,这时候可以用 Trumps 来微调

这样可以防止你的 Component 变得非常大

只有这一层才可以使用! important,以此来避免多个! important 的混乱局面

.u-color {
  &--white {
    color: $white !important;
  }
}

.u-hidden {
  display: hidden !important;
 }
复制代码

在使用时,每个分层都维护为一个文件夹。在Vue中使用时,Objects和Components相当于我们的组件,不需要单独维护。

另外值得注意的是,无论是SMACSS的分类还是ITCSS的分层,都是一种思想,我们可以根据实际项目来动态的添加或者删除某一个分类或者分层,不能生搬硬套。

设计模式:ACSS

ACSS使用了紧密的类名库。 这些类名通常被缩写,并与它们影响的内容分开。 在ACSS系统中,我们可以知道类名的作用; 但是类名称与内容类型之间没有关系,即每一个样式对应一个类,也称原子类CSS。

.float-left {
  float: left;
}
.float-right {
  float: right;
}
.z-0 {
  z-index: 0;
}
.z-auto {
  z-index: auto;
}
复制代码

从上面的代码中,可以看到ACSS有极强的复用性,维护成本低,但是破坏了css命名的语义化。最终很可能代码会成为下面这样。但是存在即合理,ACSS也有其作用,继续往下看。

<div class="grid grid-cols-3 gap-2 place-content-center h-48 ...">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
</div>
复制代码

混合使用CSS设计模式(CSS架构举例)

在进行一个项目的设计时,我们可以针对多种CSS设计模式进行选型,结合不同设计模式的优点和缺点,设计一个完整银杏的CSS架构。

举🌰:

假如我们选择ITCSS、BEM、ACSS进行组合,设计一个CSS架构。

在我们设计CSS架构时,我们首先想到的一定是SMACSS和ITCSS,因为它们两个对CSS进行了分类分层的划分。

根据上表我们可以看出ITCSS分层更加精细,所以我们选择ITCSS,接着我们继续看ITCSS的Objects和Components层,它就相当于OOCSS且相当于开发Vue组件,所以我们在开发组件时使用选择OOCSS的进阶版BEM。我们知道如果一个项目全部使用ACSS的缺点跟明显,那么我们选择ACSS的原因是因为项目中可能会存在向字体大小的这种的样式,所以我们可以把这一类样式维护在ACSS目录中。Generic和Base类似所以只保留Base即可,我假设Trumps用不到,所以也去掉这一层。所以我们的架构现在就是下面这样。

目录结构就是:

-|comments
-|styles
--|acss
--|base
--|settings
--|tools
复制代码

结束

讲到这里就该结束了,相信到这里大家就发现了,CSS设计模式离我们真的很近,我们大家日常写CSS时,所进行的优化和考量,也可以算成CSS的设计模式,可能没有联想到CSS设计模式这一概念。

设计模式提供的是一个思想,在使用时,可以灵活变化,针对不同项目或者约定,进行商定调整,整出更加银杏(人性)的CSS架构。也希望以上几个CSS设计模式,能够对大家有用。

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改