原子化 CSS 多主题切换
背景
最近给自己的歌词本加上了主题切换的功能,因为最近爱上了暗色模式,但是有的时候浏览网站突然被一个不支持暗色的网站亮瞎…访问自己的歌词本的时候也被亮瞎,才意识到网站缺少暗色模式的支持。
另外也并不打算只支持两种颜色的主题,由于原本的亮色主题是淡淡的黄色背景加上些许杂色,请教了@筱枫,取名「亚麻」,而另外两种暗色模式分别取名「黑曜」和「真黑」。设计上黑曜是打算做一个偏蓝色的暗色主题,而真黑是 rgb(0, 0, 0)
的纯黑色。(主要用于 OLED)
废话疑似有点多了…下面进入正题,谈谈在 TailwindCSS 和 Unocss 中实现多主题的方式。
实现
Unocss 这些原子化 CSS 工具的设计大体上参照的都是 TailwinCSS/WindiCSS,因此配置也类似,但不同之处在于它们支持透明度设定的方式。
而实现主题的方式则是将网站使用的颜色规范成特定命名的颜色,把它们定义在 CSS 变量中,然后更改配置以支持这些规范颜色的类名。
CSS 变量定义的方式如下:
1 |
|
这样通过切换 HTML 标签上的 data-theme
就可以影响内部通过 var
函数拿到的值,进而切换主题了。
然后在 TailwindCSS 中就可以这样配置:
1 |
|
这样任何的 text-primary
类就会被编译为 rgb(var(--color-primary))
这样的颜色值,然后通过 CSS 变量拿到实际主题中的颜色值。
在原子化 CSS 中,一般还会注入一些局部使用的 CSS 变量以便通过其他 CSS 类控制其他属性的值,例如可以这样设置文字颜色并且调整文字颜色的透明度:
1 |
|
text-slate-700
编译出的其实是这样的 CSS:
1 |
|
而 text-opacity-50
只需要控制 --tw-text-opacity
这个变量就可以了:
1 |
|
而咱们自定义的颜色类则就不能应用透明度功能了,当然你配置成 primary: 'rgb(var(--color-primary) / var(--tw-text-opacity))'
理论上也是可以的,但有一些坏处:
- 太长了
- 依赖 Tailwind 的变量前缀,在其他原子化 CSS 中可能不一致(例如 Unocss 的前缀就是
--un
) - 想不出来了(
总之 Tailwind 提供了官方的解决方案,尽量还是使用官方的解决方案,毕竟非官方提供的接口随时可能被意外改掉。Tailwind 支持在配置时传入一个函数,函数的第一个参数里面可以拿到透明度信息。
1 |
|
这样就可以支持自定义颜色的透明度设置了。
但是上述方法在 Unocss 中不奏效,咱找了很久文档也没看到说怎么自定义透明度,最后搜到了这个 issue,才知道原来 Unocss 直接内置了一个魔法,可以自动给用了 var()
的配置插入透明度,只需像不带透明度那样编写就可以,下面是 Unocss 的配置示例:
1 |
|
它会自动编译出类似这样的 CSS 类:(以文本为例)
1 |
|