Better

Ethan的博客,欢迎访问交流

组件库 CSS 样式方案

项目中一定会存在一些可被复用的组件,可能是完全自研的,也可能是基于已有组件组二次封装的。打包成一个可被不同项目间复用的 npm 包,则对待 CSS 如何处理就会有多种方式。

目标

目标:开发时能够写起来更简单,另一方面也希望使用时能更方便

常见方案

常见有如下几种方式

  • 样式和逻辑分离
  • 样式和逻辑关联
  • 样式和逻辑关联

样式和逻辑分离:组件的 CSS 和 JS 在代码层面分离,JS 里不引入样式文件,在组件库打包时分别生成独立的逻辑和样式文件。对于组件库的使用者来说,添加一个组件,需要分别引入组件代码和 CSS 文件。Ant Design 就是这么做的

  • 优点
    • 适用性广泛
    • 对外提供的是 CSS 文件,无需考虑对 SSR(服务端渲染)的支持
    • 可以直接对外提供 less、sass 等源文件,便于外部覆盖变量,实现主题定制或换肤等功能
  • 缺点
    • 需要使用者手动引入样式文件
    • 支持按需加载会比较复杂,虽然有 babel-plugin-import 辅助生成样式的 import 语句,但要求具有特定目录组织规范

样式和逻辑结合:将组件的 JS 和 CSS 打包在一起,最终只输出 JS 文件。使用时只需要引入组件就可以直接使用。

  • 方式一:CSS in JS,例如使用 styled-components、Emotion 等 CSS in JS 方案。代表组件库有 MUI 等。
  • 方式二:写代码时依然使用常规 CSS,组件内 import 样式文件,通过打包工具将 CSS 打进 JS 里。例如使用 webpack 配合 style-loader 或 rollup 配合 rollup-plugin-styles。基于这种方案的组件(库)有 react-mobile-picker、Angular Material 等。
  • 优点
    • 不需要使用者单独引入样式文件,只需要 import 组件即可使用
    • 天然支持按需加载,每个组件只需要处理自己的样式即可
  • 缺点
    • 需要带一个 runtime,可能增大代码体积,带来性能影响
    • 相较于单独的 CSS 文件,此方案的样式都在 JS 中,可能无法充分利用到浏览器缓存
    • 对 SSR 支持需要具体实现方案提供的能力

样式和逻辑关联:组件的 JS 和 CSS 在代码层面分离,打包后生成独立的逻辑和样式文件,但是组件内会直接引用样式文件,且打包结果中保留对应的 import 语句。使用这种方案的有 Semi Design、React Spectrum、Ant Design Mobile 5.0。

  • 优点
    • 如果使用者的项目能正确处理 CSS 文件,那么就可以做到只引入组件即可使用。且这种方案同样也能支持按需加载,不需要引入一个大而全的 CSS 文件
  • 缺点
    • 对组件库的开发者来说,如果使用了预处理语言,打包编译的流程会更加复杂,需要让组件最终产物的 import 语句正确关联经过编译的 CSS 文件
    • 对使用者的开发配置有一定要求,需要能正确处理由组件库内的代码引入的 CSS 文件

arco 方案

arco-design 样式方案

  • 组件和样式分离
  • 每个组件目录下定义 style 目录
    • index.less 文件编写样式
      • 引入全局 theme/default.less 文件,包含色板、间距、边框、圆角等通用全局配置
      • 引入自身 token.less 文件,定义自身支持修改的 token 变量,使用部分 CSS 变量,用于实现动态换肤
    • index.ts 供打包使用
      • 引入上述 index.less
      • 引入全局 style/index.less 文件,除 default.less 之外,包含 CSS 变量、CSS 常规化、mixin 和动画等
  • 打包过程
    • 每个组件 style 目录会生成对应的 index.css 和 index.less,以供按需加载使用
    • 会 bundle 所有组件的 index.ts,打包一份整个组件库的 index.css 和 index.less
  • 关于主题
    • 平台关于特定组件的样式修改会存在 components 中
    • 基于组件默认的 index.less + 自定义的 theme/variables/component 编译一份新的 arco.css 供使用
  • 自己组件沿用 arco 基础样式以确保一致性
    • 是否有办法 figma 审查时直接看到使用了的变量名
    • 官方 Pro 的做法:直接 style 中直接引用 CSS 变量以及复用 themes//variables.less 定义的变量

和项目结合

根据 2022 年度设计系统总结,设计系统没有明确的赢家

MUI 首席执行官兼 Material-UI 联合创始人 @Olivier Tassinari: 设计系统的空间非常分散。没有一个设计系统能超过 24% 的市场份额。这与 React 有很大的区别,React 占据了大部分的前端市场。我认为这可以简单地解释为,一个公司对设计系统的选择主要是一个 "艺术" 的选择,没有两个人有完全相同的设计品味。

正因为没有两个人由完全相同的设计品味,采用任何一个设计系统,设计师总是会想做一些修改,这通常和技术工程师需求是冲突的,我们追求一致,追求复用。与此同时,既然采用了某个设计系统,我们希望自己开发的自定义组件和三方组件遵循的规范是一致的。

关于目前项目中 CSS 编写存在的问题,以及一些思考总结

  • 存在两套 CSS 变量
    • 建议都回归到使用 arco 的变量
    • 如果需要新增,则平台新增后,更新包
  • CSS 智能提示问题,相关 vscode 可帮助我们
    • Less IntelliSense
    • CSS Variable Autocomplete
  • 主要基础样式种类:字号、字重、字色、色板、主题色、功能色、背景色、填充色、边框(大小、颜色、圆角)、阴影、常用大小、间距(spacing)、过渡动效、z-index
  • 直接使用 CSS 变量还是有语义的 less 变量:个人倾向于使用有语义的 less 变量
  • 是否允许局部定义:考虑到复用性问题,尽可能集中将变量定义在一处


留言