最近在给自己写主页(同时也是博客),我做了一个切换主题色的功能。每次进入页面时,会随机选择一套配色,让页面显得灵动一些,就像下面这样:

这是如何实现的呢?不妨先从自定义颜色入手
WindiCSS 自定义颜色
定义一个固定的颜色
这样就定义了一个 primary 的颜色,之后就能正常使用了,(如 bg-primary / text-primary)
当然,不仅可以传递字符串,还能够使用对象定义一组颜色:(如 bg-primary-light)
使用CSS变量
为了使颜色可变,使用 CSS 变量会方便许多,WindiCSS 当然也是支持的:
这样就能够基本实现在 WindiCSS 中使用 CSS 变量了,不过还有一个小问题:
WindiCSS 支持为颜色设置透明度,例如 bg-gray-800/80 bg-gray-800 bg-opacity-80 这两种写法。上面的配置方式会导致这种语法失效(丢失透明度)。所以,我们需要给CSS变量换一种形式。同时,需要一个高阶工具函数来包装一下变量:
如此一来,每当使用 primary 颜色时,WindiCSS 都会调用函数来生成样式,通过对 opacityValue 的判断来实现对透明度语法的支持。
SCSS 生成 CSS 变量
显然,如果手动为 light extralight 等颜色变种指定颜色值是不现实的,况且现在需要用 R G B 三个数字来表示颜色,编辑器没有高亮,不直观,也会导致维护困难。
这时候SCSS就能派上用场了!SCSS提供了基础的CSS数据类型,判断、遍历语法,同时也提供了海量的工具函数(例如 red() blue() green()等用于通道分离,mix()用于颜色混合)
首先来实现一个工具函数,将传入的十六进制颜色转换成 R G B 三个数字的形式
我预想中的情况是——只要给一个 primary 的基础色,SCSS就能帮我把 light extralight 等颜色变种都生成出来。我是用 mix 方法来实现:
这样,就能针对某一个颜色生成对应的系列颜色属性了。接下来,只需要定义一个数组,把需要的主题色放进去,跑个循环即可(从 Material Design 的文档里随便挑了几个养眼的颜色):
在VSCode中,看起来是这样的:

显然舒服多了。
剩下的工作该划掉了
如果希望修改主题色,只需要给根元素(html 或 body)增加对应类名即可(例如 theme-1 / theme-2),实现的方式很多,因为我使用了 Nuxt.js,下面是我的解决方案。