最近在给自己写主页(同时也是博客),我做了一个切换主题色的功能。每次进入页面时,会随机选择一套配色,让页面显得灵动一些,就像下面这样:
这是如何实现的呢?不妨先从自定义颜色入手
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,下面是我的解决方案。