最近給 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