最近给 xLog 增加了黑暗模式的支持,但由于 xLog 在开发时候就没对黑暗模式留个口子,比如颜色值不固定写死,或者是使用 CSS 变量的颜色值。而 xLog 真巧使用了 Tailwind,基本上所有的颜色应用场景都用了 Tailwind 自带的色值,但由于 Tailwind 本身自带的色值都是一个固定的值,并不支持根据 Dark Mode 切换色值。
于是我萌生了一个想法,让自带的颜色能根据是否是暗黑模式去切换就行了。
首先第一是,要重新配置 Tailwind,覆写原来内置的所有的颜色,把固定的值全部改写成 CSS 变量。变量的前缀可以自定义,不要冲突就行了,这边就暂定为 tw-colors-i
。比如我们需要类似这样的色值配置:
// tailwind.config.ts
module.exports = {
theme: {
colors: {
slate: {
50: 'rgb(var(--tw-colors-i-slate-50))',
100: 'rgb(var(--tw-colors-i-slate-100))',
// ...
},
},
},
}
但是以上的写法并不支持 Tailwind 的让颜色获得 Opacity 的能力,所以还需要修改一下。
// tailwind.config.ts
module.exports = {
theme: {
colors: {
slate: {
50: 'rgba(var(--tw-colors-i-slate-50), <alpha-value>)',
100: 'rgba(var(--tw-colors-i-slate-100), <alpha-value>)',
// ...
},
},
},
}
加上 <alpha-value>
用于被 Tailwind 替换相应的 Opacity。注意这里我们使用了 rgba
所以后续在定义颜色变量的时候要注意,不能使用 Hex 类型的颜色值,而要使用类似这样的格式 --tw-colors-i-slate-50: 248, 250, 252;
。
接下来就是如何取反色的问题,在 Tailwind 3.3 以上的版本,内置颜色都是从 50
开始到 950
结束(3.2 版本没有 950
)。一个亮色对应一个暗色,并且相加等于 1000
。比如,slate-50
对应的暗色就是 slate-950
, 90+950=1000
。按照这个思路,就可以写一个脚本去生成一个暗色的所有的色值。
代码这里就不贴了,可以去 Crossbell-Box/xLog 这里看,如果需要使用的话只需要修改下,生成的 CSS 路径和 Tailwind 色值配置的路径即可(Tailwind >= 3.3)。
生成的 CSS 颜色变量定义大概长这样(截取部分,完整可以通过 Crossbell-Box/xLog 查看):
:root {
--tw-colors-i-slate-50: 248, 250, 252;
--tw-colors-i-slate-100: 241, 245, 249;
--tw-colors-i-slate-200: 226, 232, 240;
--tw-colors-i-slate-300: 203, 213, 225;
--tw-colors-i-slate-400: 148, 163, 184;
--tw-colors-i-slate-500: 100, 116, 139;
}
html.dark {
--tw-colors-i-slate-50: 2, 6, 23;
--tw-colors-i-slate-100: 15, 23, 42;
--tw-colors-i-slate-200: 30, 41, 59;
--tw-colors-i-slate-300: 51, 65, 85;
--tw-colors-i-slate-400: 71, 85, 105;
--tw-colors-i-slate-500: 100, 116, 139;
}
html.light {
--tw-colors-i-slate-50: 248, 250, 252;
--tw-colors-i-slate-100: 241, 245, 249;
--tw-colors-i-slate-200: 226, 232, 240;
--tw-colors-i-slate-300: 203, 213, 225;
--tw-colors-i-slate-400: 148, 163, 184;
--tw-colors-i-slate-500: 100, 116, 139;
}
@media (prefers-color-scheme: dark) {
html:not(.light) {
--tw-colors-i-slate-50: 2, 6, 23;
--tw-colors-i-slate-100: 15, 23, 42;
--tw-colors-i-slate-200: 30, 41, 59;
--tw-colors-i-slate-300: 51, 65, 85;
--tw-colors-i-slate-400: 71, 85, 105;
--tw-colors-i-slate-500: 100, 116, 139;
}
}
@media (prefers-color-scheme: light) {
html:not(.dark) {
--tw-colors-i-slate-50: 248, 250, 252;
--tw-colors-i-slate-100: 241, 245, 249;
--tw-colors-i-slate-200: 226, 232, 240;
--tw-colors-i-slate-300: 203, 213, 225;
--tw-colors-i-slate-400: 148, 163, 184;
--tw-colors-i-slate-500: 100, 116, 139;
}
}
这个 CSS 中定义了在系统在暗色还是亮色以及根据 html.light
html.dark
确定亮暗色。
同时生成 Tailwind 颜色配置:
// tw-colors.js
export default {
slate: {
50: "rgba(var(--tw-colors-i-slate-50), <alpha-value>)",
100: "rgba(var(--tw-colors-i-slate-100), <alpha-value>)",
200: "rgba(var(--tw-colors-i-slate-200), <alpha-value>)",
300: "rgba(var(--tw-colors-i-slate-300), <alpha-value>)",
400: "rgba(var(--tw-colors-i-slate-400), <alpha-value>)",
500: "rgba(var(--tw-colors-i-slate-500), <alpha-value>)",
600: "rgba(var(--tw-colors-i-slate-600), <alpha-value>)",
700: "rgba(var(--tw-colors-i-slate-700), <alpha-value>)",
800: "rgba(var(--tw-colors-i-slate-800), <alpha-value>)",
900: "rgba(var(--tw-colors-i-slate-900), <alpha-value>)",
950: "rgba(var(--tw-colors-i-slate-950), <alpha-value>)",
},
// ...
inherit: "inherit",
current: "currentColor",
transparent: "transparent",
black: "rgba(var(--tw-colors-i-black), <alpha-value>)",
white: "rgba(var(--tw-colors-i-white), <alpha-value>)",
}
在项目中,引入生成的 CSS,并在 Tailwind 配置覆写颜色。
// tailwind.config.js
const twColors = require("./tw-colors")
const alwaysColor = require("tailwindcss/colors")
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.tsx"],
darkMode: ['class', 'html.dark'],
theme: {
colors: twColors,
extend: {
colors: {
always: alwaysColor
}
}
}
}
这里可选配置定义下 always
,always 的颜色仍是自带的固定颜色值。如有需要可以取用。
至于 darkMode
是否需要定义,现在变成了可选项,如果需要用 Tailwind 提供的 dark-mode:
那是需要开启的。不过既然都是动态色值了,开不开就按使用需求了。
说说缺点:
- 引入了大量 CSS 变量,并且无用变量无法在编译时消除。
更好的解决方式?
给 Tailwind 提 PR。支持颜色多重定义,如下所示:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./src/**/*.tsx'],
theme: {
colors: {
blue: {
50: {
light: '#123',
dark: '#321',
},
},
},
},
}
希望有 Tailwind 的小伙伴可以看到这个提案。
最后安利一下 xLog,这么好用的博客平台,还不赶紧试试?
对了,我自创的 Mix Space 现也支持同步到 xLog 了,赶紧来试试吧。
此文由 Mix Space 同步更新至 xLog
原始链接为 https://innei.ren/posts/programming/tailwind-built-in-colors-dark-mode