项目中一定会存在一些可被复用的组件,可能是完全自研的,也可能是基于已有组件组二次封装的。打包成一个可被不同项目间复用的 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 和动画等
- index.less 文件编写样式
- 打包过程
- 每个组件 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 变量
- 是否允许局部定义:考虑到复用性问题,尽可能集中将变量定义在一处