需求分析
现有方案缺陷
- CSS 变量
无法支持复杂表达式 mix(var(–primary-color), #fff, 20%)
浏览器兼容性有限(ie 不支持)
- 多套 CSS 主题
主题样式固定,无法实时切换主题色
CSS 代码分离不好处理
- less 动态切换
需要引入 less runtime 体积较大
切换主题时会对整个样式表进行 parse -> eval -> genCSS 处理,导致切换速度很慢
想要实现的目标
- 支持实时修改 @primary-color, @border-radius-base 之类的参数
- 浏览器页面刷新后默认就是切换后的样式,没有多余的动画、明显的加载过程
- 打包体积小,无需打包多个样式文件
- 代码分离友好,不同页面的样式可以分别加载
实现方案
方案一
-
原理:通过类覆盖的方式来动态修改颜色,因为 CSS 加载机制是由上至下,同名会覆盖对应属性。
-
开源实现:dynamic-antd-theme github.com/luffyZh/dyn…
-
评论:做了很多重复大量的 css 操作来覆盖类名,只做了@primaryColor 相关的覆盖,其他覆盖仍然需要:global 或者组件内覆盖这种方式。有现成的即插即用换肤插件,直接使用。
方案二
-
原理:编译时把不同皮肤需要修改的 less 变量、表达式留空, 在运行时填充。
-
开源实现:antd-theme github.com/wuzekang/an…
-
评论:开箱即用。存在限制:
1、postcss-position 不兼容。
postcss-position 会直接对 css 中的 position 属性值进行 value.match(/^static|absolute|fixed|relative…/).toString(),而 ‘”[theme:position,default:relative]”‘.match(…) === null
因此会出现在编译过程中的报错,具体的 postcss-position 代码在这里: github.com/seaneking/p…
2、递归 Mixin Call 的循环变量不能作为皮肤变量, 比如 ant-design 栅格系统相关代码中的 @grid-columns
.loop-grid-columns(@index, @class) when (@index > 0) {
.@{ant-prefix}-col@{class}-order-@{index} {
order: @index;
}
.loop-grid-columns((@index - 1), @class);
}
.loop-grid-columns(@grid-columns, @class);
复制代码
方案三
-
原理:通过 webpack 插件形式将样式文件解析后将更换主题的代码注入到每个 js 头部。
-
开源实现:webpack-theme-color-replacer github.com/hzsrc/webpa…
-
评论:需要额外再代码中引入样式替换的 js,无需在页面进行 less 的编译,提升了切换速度。
方案四
-
原理:发布线上之前就将 CSS 解析好,线上的时候只需要解析这些已经处理好的样式文件即可。灵感源于方案三。
-
开源实现:webpack-stylesheet-variable-replacer-plugin github.com/eaTong/webp…
-
评论:支持 key–value 方式来定义需要替换的变量,还有就是注入文件可控,不会重复注入,方便使用。