From 81748e447023704b6e9de107fc5729ac74ca6b78 Mon Sep 17 00:00:00 2001 From: Bill Date: Fri, 16 Oct 2026 23:44:48 +0800 Subject: [PATCH] =?UTF-8?q?fix(theme):=20=E6=B5=85=E8=89=B2=E4=B8=BB?= =?UTF-8?q?=E9=A2=98=E6=A0=87=E7=AD=BE=E5=BC=BA=E8=B0=83=E8=89=B2=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E6=8C=89=20WCAG=20=E5=8A=A0=E6=B7=B1=EF=BC=88?= =?UTF-8?q?=E5=AE=9E=E6=B5=8B=204.0:1=20->=204.9:1=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 浅色分支此前固定 mix(accent, #000, 0.35),默认绿 #3fb950 得 #297834:在强调色 染过的激活标签底(≈#dae8df)上只有 4.0:1,低于 AA,用户自定义的浅色强调色还会 更差。改用 darkenToRatio(accent, chromeBg, 5.5)——对 chrome 底色保证 5.5:1, 落到更深的染色底上仍有 4.9:1。深色分支(mix 白 0.18)不动。 chrome.ts 新增 chromeBg 记录当前 chrome 底色(applyTabAccent 可能在 applyChromeTheme 之前被设置变更单独调用);#181818 是 pre-JS 深色默认值, 登记进 css-theme-vars 白名单(与 global.css 的 --chrome-bg 同值)。 --- src/renderer/src/theme/chrome.ts | 15 +++++++++++++-- tests/css-theme-vars.mjs | 3 ++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/renderer/src/theme/chrome.ts b/src/renderer/src/theme/chrome.ts index a2e716b..766f4e4 100644 --- a/src/renderer/src/theme/chrome.ts +++ b/src/renderer/src/theme/chrome.ts @@ -1,5 +1,5 @@ import type { ThemeColors } from '@shared/theme' -import { contrast, isLightTheme, mix, semanticCssVars } from './semantic' +import { contrast, darkenToRatio, isLightTheme, mix, semanticCssVars } from './semantic' // 兼容既有导入方(main.tsx 的 mix);新代码请直接从 ./semantic 导入。 export { contrast, luminance, mix } from './semantic' @@ -8,6 +8,10 @@ export { contrast, luminance, mix } from './semantic' * from it flip their overlay direction (white-on-dark vs black-on-light). */ let chromeIsLight = false +/** Last chrome background; applyTabAccent() needs it to derive a readable + * accent foreground for light themes. */ +let chromeBg = '#181818' + /** Dark-chrome tab label: the background mixed toward the theme's own foreground * (the light branch is the same mix toward black), but never below 4.5:1 against * the background, since a theme foreground dimmed by 0.68 can land unreadable. */ @@ -32,6 +36,7 @@ export function applyChromeTheme(colors: ThemeColors): void { set('--chrome-bg', colors.background) set('--chrome-fg', colors.foreground) chromeIsLight = isLightTheme(colors.background) + chromeBg = colors.background if (chromeIsLight) { // Light chrome: keep the bar close to the background (a big mix toward // black turns pale themes into a muddy gray strip) and overlay tabs with @@ -82,6 +87,12 @@ export function applyTabAccent(color: string): void { return } style.setProperty('--tab-accent', color) - const fg = chromeIsLight ? mix(color, '#000000', 0.35) : mix(color, '#ffffff', 0.18) + // Light chrome: a fixed 0.35 mix toward black left the default green + // (#3fb950 -> #297834) at 4.0:1 on the accent-tinted tab, just under AA, and + // arbitrary user accents could be far worse. darkenToRatio() guarantees the + // ratio against the chrome background; the tinted surfaces it also lands on + // are slightly darker, hence the margin above 4.5. Dark chrome keeps the + // existing lighten mix (its accents sit on dark tabs). + const fg = chromeIsLight ? darkenToRatio(color, chromeBg, 5.5) : mix(color, '#ffffff', 0.18) style.setProperty('--tab-accent-fg', fg ?? color) } diff --git a/tests/css-theme-vars.mjs b/tests/css-theme-vars.mjs index b1c096c..bae348b 100644 --- a/tests/css-theme-vars.mjs +++ b/tests/css-theme-vars.mjs @@ -16,8 +16,9 @@ const WHITELIST = { // The layer that DEFINES the anchors and derives per-theme values. 'theme/semantic.ts': null, // Pre-existing --chrome-* derivation anchors (mix targets / overlay bases). + // #181818 = global.css --chrome-bg, the pre-JS chromeBg default. 'theme/chrome.ts': new Set([ - '#000000', '#ffffff', + '#000000', '#ffffff', '#181818', 'rgba(0, 0, 0, 0.045)', 'rgba(0, 0, 0, 0.09)', 'rgba(0, 0, 0, 0.18)', 'rgba(0, 0, 0, 0.32)', 'rgba(255, 255, 255, 0.04)', 'rgba(255, 255, 255, 0.07)', 'rgba(255, 255, 255, 0.1)', 'rgba(255, 255, 255, 0.2)' ]),