6

Vue3 企业级优雅实战 - 组件库框架 - 4 组件库的 CSS 架构 - 程序员优雅哥(\/同)

 1 year ago
source link: https://www.cnblogs.com/youyacoder/p/16889014.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

该系列已更新文章:
分享一个实用的 vite + vue3 组件库脚手架工具,提升开发效率
开箱即用 yyg-cli 脚手架:快速创建 vue3 组件库和vue3 全家桶项目
Vue3 企业级优雅实战 - 组件库框架 - 1 搭建 pnpm monorepo
Vue3 企业级优雅实战 - 组件库框架 - 2 初始化 workspace-root
Vue3 企业级优雅实战 - 组件库框架 - 3 搭建组件库开发环境

在前一篇文章中分享了搭建组件库的基本开发环境、创建了 foo 组件模块和组件库入口模块,本文分享组件库的样式架构设计。

1 常见的 CSS 架构模式

常见的 CSS 架构模式有很多:OOCSSACSSBEMSMACSSITCSS 等,其中 SMACSSITCSS 很相似。我在企业级项目中最常使用的是简化版的 ITCSS + BEM + ACSS,所以本文首先介绍这三种模式,其他模式大家自己上网查看。

1.1 ACSS

ACSS 模式几乎是一个样式属性就对应了一个样式类。这种方式非常灵活,复用性很强、维护成本低,但破坏了 CSS 命名语义化。常见的名称如:d-flex、m-10、w-20 等。

1.2 BEM

BEM 模式是一种命名方法论,其命名层级为:Block元素 Element修饰符 Modifier,这也是 “BEM” 这个名字的由来。元素 Element 使用两个短下划线(__),修饰符 Modifier 使用两个短中划线(--),如下面的 HTML 片段和对应的类名:

<div class="demo-block">
  <a class="demo-block__element1">Link</a>
  <a class="demo-block__element1 demo-block__element1--modifier">Link</a>
</div>

<style>
  .demo-block {} // 块
	.demo-block__element1 {} // 元素
	.demo-block__element1--modifier1 {} // 修饰符
</style>

使用 BEM 可以规范命令,页面结构也比较清晰。

1.3 ITCSS

ITCSS 是一种样式的分层结构,一共有七层,七个层次从上到下依次为:

  • Settings 层:通常是一些样式变量,如定义通用的颜色值、字体大小的数值等;
  • Tools 层:通用工具函数,包括 mixins、function 等;
  • Generic 层:通用基础样式,一般是对浏览器默认样式进行重置,如 normalize.css、resets 等库;
  • Base 层:对某些全局使用的元素进行通用的定制化样式,如页面的设置、ul 标签的设置等;
  • Objects 层:所有使用 OOCSS 的地方,即某些结构和样式相分离的专用类;
  • Components 层:具体的组件,其实可以对应到组件库中的每个组件;
  • Trumps 层:重写某些样式,如 width 重新设置为 100px,只会影响某一小块的 DOM 元素,权重最高,类似 ACSS,但通常会加上 !important

2 组件库的 CSS 架构

ITCSS 分层非常细致,咱们组件库的样式在其基础上进行了简化,省略了 Base 层 或 Objects 层。而对于 Trumps 层,咱使用 ACSS 来替代,对于 Components 层,里面的每个组件内部又使用 BEM。所以咱们组件库的样式架构为:简化版的 ITCSS + BEM + ACSS。

2.1 CSS 结构概览

组件库的样式使用预处理器 SCSS,从结构整体来看,分为如下层级:

  • base 层:整个 CSS 结构的最基础的层级,对应了 ITCSS 的 Settings、Generic 和 Base。即包括变量定义、通用基础样式和定制基础样式。
  • tools 层:与 ITCSS 的 Tools 一样,提供通用工具函数。
  • acss 层:类似 ITCSS 的 Trumps,定义一些原子样式类,如 flex、margin、padding 相关的样式基础类。
  • components 层:与 ITCSS 的 Components 一样,实现各个组件的样式,其中每个组件的样式又使用 BEM 方式来组织命名。

2.2 base 层的实现

前面说过,base 层包括样式变量定义、通用基础样式、定制基础样式。

首先在 packages/scss 目录下创建 base 目录,存放 base 层的 scss 文件。

  1. settings

settings 是一些变量的定义,在 packages/scss/base/ 目录中创建 _var.module.scss 文件,该文件定义样式变量。

$primary-color: #488019;
$common-padding: 20px;

:export {
  primaryColor: $primary-color;
}
  1. Generic

Generic 通常是对浏览器样式的重置,统一 HTML 标签在不同浏览器中的展示,屏蔽浏览器间的差异。在这个部分可以使用开源库normalize.cssreset.css 等。这一层可以在组件库中省略,在各个具体的应用中引入对应css。不过程序员优雅哥还是将浏览器样式重置引入到组件库中,这样应用开发过程中省点事。咱使用开源的 normalize.css 作为 Genericnormalize.css 的代码可以在 GitHub 上搜索获取。

image-20221113203109334

继续在 packages/scss/base/ 目录中创建 _normalize.scss 文件,将 normalize.css 的内容直接复制进去就可以了。

  1. Base

Base 主要是存放部分重置样式的自定义,如 html、body、section 等,这部分咱们暂时没有自定义的内容,就无需编写了。

  1. 入口文件

最后需要将 base 层所有 scss 以统一的入口引入。在 packages/scss/base/ 目录下创建 index.scss,该文件导入上面创建的两个 scss 文件:

@use "var.module";
@use "normalize";

2.3 tools 层的实现

tools 层用于存放工具函数和 mixins,github 上有个优秀的开源项目 sassMagic,咱们就使用它作为 tools 层。

image-20221113210129530

将该项目 src 中的代码拷贝到 packages/scss/tools/ 目录下即可(如果 _sassMagic.scss 文件中有报错,将里面对不存在文件的引入删除即可)。我在这里将 _sassMagic.scss 文件重命名为 index.scss,这样后面在使用时只需要使用 @use "../tools" 即可。

2.4 acss 层的实现

acss 层用于定义一些原子样式,这里咱们定义 flex 布局和 margin/padding 的原子类。

packages/scss/ 中创建目录 acss,并在该目录下创建两个文件:_flex.scss_mp.scss

packages/scss/acss/_flex.scss

.f {
  display: flex;
}
.f-c {
  display: flex;
  flex-direction: column;
}
.f-r {
  display: flex;
  flex-direction: row;
}
.f-1 {
  flex: 1 1 0;
}
.oy-h {
  overflow-y: hidden;
}
.oy-a {
  overflow-y: auto !important;
}
.ox-h {
  overflow-x: hidden;
}
.o-h {
  overflow: hidden;
}

packages/scss/acss/_mp.scss

$direction: (l left, r right, t top, b bottom);

@for $i from 1 through 30 {
  @each $type in m, p, v, h, a {
    // margin
    @if ($type == m) {
      @each $d in $direction {
        .m#{nth($d, 1)}-#{$i} {
          margin-#{nth($d, 2)}: #{$i}px;
        }
      }
    }
    // padding
    @else if ($type == p) {
      @each $d in $direction {
        .p#{nth($d, 1)}-#{$i} {
          padding-#{nth($d, 2)}: #{$i}px;
        }
      }
    }
    // margin/padding left/right
    @else if ($type == h) {
      .ph-#{$i} {
        padding-left: #{$i}px;
        padding-right: #{$i}px;
      }
      .mh-#{$i} {
        margin-left: #{$i}px;
        margin-right: #{$i}px;
      }
    }
    // margin/padding top/bottom
    @else if ($type == v) {
      .mv-#{$i} {
        margin-top: #{$i}px;
        margin-bottom: #{$i}px;
      }
      .pv-#{$i} {
        padding-top: #{$i}px;
        padding-bottom: #{$i}px;
      }
    }

    // all
    @else {
      .pa-#{$i} {
        padding: #{$i}px;
      }
    }
  }
}

2.5 components 层的实现

components 层对应组件库中每个具体组件的样式。在 packages/scss 中创建目录 components。首先为上一篇文章中创建的 foo 组件创建样式:在 packages/scss/components/ 目录下创建 _foo.module.scss 文件:

@import "../tools";
@import "../acss/mp";
@import "../base/var.module";

@include b('yyg-foo') {
  color: $primary-color;

  @include e('description') {
    color: #333333;
    @extend .mv-20;
  }
}

继续在 packages/scss/components/ 目录下创建 index.scss 文件,该文件中引入 components 目录下所有组件的 scss 文件:

@use "foo.module";

如果新增了其他组件,需要在 components 目录下创建该组件的样式文件,并在 components/index.scss 中引入该 scss 文件。

2.6 样式入口

packages/scss 下创建 index.scss,在里面导入所有的 scss,使用组件库时只需要引入该文件即可。

@import "./acss/flex";
@import "./base";
@import "./components";

3 在组件库中引入样式

最后只需要在组件库中引入 scss/index.scss 即可。在组件库的入口模块 packages/yyg-demo-ui/index.ts 中引入 index.scss

import '../scss/index.scss'

(在上文中的代码已经包括这一句引入了)

到此便完成了组件库样式架构的搭建,整个样式的目录结构如下:

image

感谢你阅读本文,如果本文给了你一点点帮助或者启发,还请三连支持一下,点赞、关注、收藏,程序员优雅哥会持续与大家分享更多干货


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK