diff --git a/ry-vue3/src/assets/theme.js b/ry-vue3/src/assets/theme.js index 76dc08c..64cbacb 100644 --- a/ry-vue3/src/assets/theme.js +++ b/ry-vue3/src/assets/theme.js @@ -9,13 +9,10 @@ * setBrandSecondary('#009963', { persist: true }) // 改次色 (绿) * applyStoredBrands() // 启动时调用, 同时应用两个 * - * 派生色算法(HSL 空间调整,比简单 hex 加减更稳): - * deep: lightness -= 12 - * darker: lightness -= 22 - * light: lightness += 12 - * lighter: lightness += 35 - * text: lightness += 22 - * mix: 50% alpha + white (用于 focus border) + * 派生色算法(双轨, 跟 theme.scss :root 保持一致): + * 深色 deep/darker — HSL lightness 调整 (适合 hover/active/导航) + * 浅色 light/lighter/text/mix — Element Plus mix(white, base, N*10%) + * (RGB 线性插值, 不会像 HSL +35% 那样生成荧光色, 适合政务网站) * * 双色系: 主色 (primary, 青蓝) + 次色 (secondary, 翠绿). * 主色 → Element Plus --el-color-primary*; 次色 → --el-color-success* (绿=成功语义). @@ -77,10 +74,35 @@ function hslToHex({ h, s, l }) { /** 把 lightness 限制在 8..92 之间 */ function clampL(l) { return Math.max(8, Math.min(92, l)) } +/** + * Element Plus mix() — RGB 线性插值 (Sass mixColor 复刻) + * mix(color1, color2, weight) → color1*(1-w) + color2*w + * 比 HSL 大幅提亮更克制, 适合政务网站的浅色调. + */ +function elMix(color1, color2, weight) { + weight = Math.max(Math.min(weight, 1), 0) + const r1 = parseInt(color1.slice(1, 3), 16), g1 = parseInt(color1.slice(3, 5), 16), b1 = parseInt(color1.slice(5, 7), 16) + const r2 = parseInt(color2.slice(1, 3), 16), g2 = parseInt(color2.slice(3, 5), 16), b2 = parseInt(color2.slice(5, 7), 16) + const r = Math.round(r1 * (1 - weight) + r2 * weight) + const g = Math.round(g1 * (1 - weight) + g2 * weight) + const b = Math.round(b1 * (1 - weight) + b2 * weight) + return '#' + [r, g, b].map(v => v.toString(16).padStart(2, '0')).join('') +} + /** * 通用派生算法:输入主色 hex, 输出 7 个 --brand--* 变量 * @param {string} base 主色 hex * @param {string} [prefix='primary'] 变量名前缀 (primary / secondary) + * + * 派生算法 (跟 theme.scss :root 保持一致): + * 深色 (HSL lightness): + * deep = L - 12 (hover / active / 标题强调) + * darker = L - 22 (顶部导航 / 深底) + * 浅色 (Element Plus mix(white, base, N*10%)): + * light = 50% mix (背景 / disabled) + * lighter = 70% mix (hover-bg / 选中态) + * text = 30% mix (链接默认) + * mix = 80% mix (输入框 focus border) */ export function derivePalette(base, prefix = 'primary') { const hsl = rgbToHsl(hexToRgb(base)) @@ -89,10 +111,10 @@ export function derivePalette(base, prefix = 'primary') { [`--brand-${p}`]: base, [`--brand-${p}-deep`]: hslToHex({ ...hsl, l: clampL(hsl.l - 12) }), [`--brand-${p}-darker`]: hslToHex({ ...hsl, l: clampL(hsl.l - 22) }), - [`--brand-${p}-light`]: hslToHex({ ...hsl, l: clampL(hsl.l + 12) }), - [`--brand-${p}-lighter`]: hslToHex({ ...hsl, l: clampL(hsl.l + 35) }), - [`--brand-${p}-text`]: hslToHex({ ...hsl, l: clampL(hsl.l + 22) }), - [`--brand-${p}-mix`]: hslToHex({ ...hsl, l: clampL(hsl.l + 45) }) + [`--brand-${p}-light`]: elMix('#ffffff', base, 0.5), + [`--brand-${p}-lighter`]: elMix('#ffffff', base, 0.7), + [`--brand-${p}-text`]: elMix('#ffffff', base, 0.3), + [`--brand-${p}-mix`]: elMix('#ffffff', base, 0.8) } } diff --git a/ry-vue3/src/assets/theme.scss b/ry-vue3/src/assets/theme.scss index 93e4590..3c28ad1 100644 --- a/ry-vue3/src/assets/theme.scss +++ b/ry-vue3/src/assets/theme.scss @@ -4,22 +4,24 @@ 所有色值都是 HSL/HEX 函数动态计算的派生色。 改 :root 里的 --brand-primary / --brand-secondary 即可全局换色。 - 派生色算法(hex → HSL → 调整亮度/饱和 → 转回 hex): - --brand-primary 主色 - --brand-primary-deep 暗 12% (hover / active / 标题强调) - --brand-primary-darker 暗 22% (顶部导航 / 深底) - --brand-primary-light 浅 22% (背景 / disabled) - --brand-primary-lighter 浅 55% (hover-bg / 选中态) - --brand-primary-text 浅 35% (链接默认) - --brand-primary-mix 50% 透明 + 白 (输入框 focus border) + 派生色算法(双轨): + 深色 (deep/darker) — HSL 调亮度 + --brand-primary-deep 暗 12% (hover / active / 标题强调) + --brand-primary-darker 暗 22% (顶部导航 / 深底) + 浅色 (light/lighter/text/mix) — Element Plus mix(white, base, N*10%) + --brand-primary-light mix 50% white (背景 / disabled) + --brand-primary-lighter mix 70% white (hover-bg / 选中态) + --brand-primary-text mix 30% white (链接默认) + --brand-primary-mix mix 80% white (输入框 focus border) + 之前 HSL +35% 算法会生成荧光色 (例 #49deff), 政务网站不适用; + 改用 Element mix() 才是 RGB 线性插值, 全是低饱和度灰调. - 次色(绿色 #009963)— 走同一套派生算法, 命名 -secondary。 + 次色 (绿色 #009963) 走同一套算法, 命名 -secondary. 语义上对应 Element Plus success (绿=成功/已批准/已完成), 自动 - 绑定到 --el-color-success*, 这样所有 / - el-tag type="success" 等都跟随品牌绿。 + 绑定到 --el-color-success*. - Element Plus 同步:main.js 在启动时读取两个 CSS 变量 - 并通过 ElMessage / ElButton 的 --el-color-* 联动。 + Element Plus 同步:main.js 在启动时读取 --brand-primary 并联动 + ElMessage / ElButton 的 --el-color-primary. ============================================================= */ :root { @@ -27,19 +29,19 @@ --brand-primary: #007A95; --brand-primary-deep: #004858; --brand-primary-darker: #002129; - --brand-primary-light: #00acd2; - --brand-primary-lighter: #49deff; - --brand-primary-text: #06d2ff; - --brand-primary-mix: #7ce7ff; + --brand-primary-light: #80bdca; + --brand-primary-lighter: #4da2b5; + --brand-primary-text: #b3d7df; + --brand-primary-mix: #3395aa; /* 次色 — 翠绿 */ --brand-secondary: #009963; --brand-secondary-deep: #005c3b; --brand-secondary-darker: #00291a; - --brand-secondary-light: #00d68b; - --brand-secondary-lighter: #4dffc0; - --brand-secondary-text: #0affa9; - --brand-secondary-mix: #80ffd2; + --brand-secondary-light: #80ccb1; + --brand-secondary-lighter: #4db892; + --brand-secondary-text: #b3e0d0; + --brand-secondary-mix: #33ad82; } /* Element Plus 联动:把品牌色同步给 Element Plus 内置变量。 @@ -47,16 +49,16 @@ :root { /* 主色 → primary */ --el-color-primary: var(--brand-primary); - --el-color-primary-light-3: var(--brand-primary-light); - --el-color-primary-light-5: var(--brand-primary-lighter); - --el-color-primary-light-7: var(--brand-primary-lighter); - --el-color-primary-light-9: var(--brand-primary-lighter); + --el-color-primary-light-3: var(--brand-primary-text); /* text */ + --el-color-primary-light-5: var(--brand-primary-light); /* light */ + --el-color-primary-light-7: var(--brand-primary-lighter); /* lighter */ + --el-color-primary-light-9: var(--brand-primary-lighter); /* lighter */ --el-color-primary-dark-2: var(--brand-primary-deep); /* 次色 → success (绿色语义: 已批准 / 已完成) */ --el-color-success: var(--brand-secondary); - --el-color-success-light-3: var(--brand-secondary-light); - --el-color-success-light-5: var(--brand-secondary-lighter); + --el-color-success-light-3: var(--brand-secondary-text); + --el-color-success-light-5: var(--brand-secondary-light); --el-color-success-light-7: var(--brand-secondary-lighter); --el-color-success-light-8: var(--brand-secondary-lighter); --el-color-success-light-9: var(--brand-secondary-lighter);