下拉框改回软件主题色;修 color-mix 与变量配合失效的问题

用户:「下拉框的颜色就用那个软件的主题颜色,不行吗?现在怎么还是都是灰的呀?
我感觉用主题颜色就行,挺好看的。」

上一版我判断错了:看到同步日历主题色 #ff3f44 算出的 --brand-soft 是 #ffe8e9(粉),
就自己决定换成中性灰,理由写的是"工具控件不该跟主题色"。
这是替用户做审美决定,而且用户要的恰恰是「跟着软件变颜色」——
这正是这套系统区分不同软件的核心手段。已改回主题色系。

改了什么:
- 下拉项 hover  → --brand-tint-1(主题色与白混 91%)
- 下拉项选中    → --brand-tint-2(混 80%,比 hover 深一档)
- 选中项 hover  → --brand-tint-3(混 72%,再深一点)
- 按钮打开态:浅主题底 + 主题边框 + 主题文字
- 箭头打开时转 180 并染成主题色

关键技术问题:
最初想用 CSS 的 color-mix(in srgb, var(--brand) 9%, #fff) 动态算浅色。
实测在 Chrome 里虽然 CSS.supports 返回 true、规则也匹配上了,
但计算值却是 oklab(0 0 0 / 0)(完全透明)—— 变量在 color-mix 里解析失败。
改成在 PHP 里用 fb_color_tint() 把值算好,
以 --brand-tint-1/2/3 三个 CSS 变量输出。
好处:不依赖浏览器版本,也没有运行时开销。
默认(无当前软件的页面,如后台)在 :root 里给了蓝色的一套兜底值。

验证(真实页面 + 真实鼠标事件):
  feedlite      #0057b8 → 选中 rgb(184,208,235) 浅蓝
  synccalendar  #ff3f44 → 选中 rgb(255,201,203) 浅红
  simple_password #a556f7 → 选中 rgb(230,208,253) 浅紫
  simplenav     #3571fb → 选中 rgb(198,215,254) 亮蓝
  真实 mousemove 悬停:背景 rgb(255,238,238),:hover 匹配为 true
  选中项 rgb(255,201,203) 明显深于 hover rgb(255,238,238),两者可区分

踩坑记录:中途用 JS 加 is-active 类来测 hover 只能触发 .is-active,
必须发真实 mouseMoved 事件才能验证 :hover,否则会误判成"样式失效"。
This commit is contained in:
2026-11-04 19:31:55 +08:00
parent 9b971a5b92
commit 8db38a834d
4 changed files with 88 additions and 15 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ if (!defined('FB_ROOT')) {
define('FB_ROOT', dirname(__DIR__));
// 静态资源版本号:改 assets/ 下的 css/js 后把这个数字 +1,
// 让浏览器与 CDN 缓存失效。全站只此一处,别再往页面里写死数字。
if (!defined('FB_ASSET_V')) { define('FB_ASSET_V', 49); }
if (!defined('FB_ASSET_V')) { define('FB_ASSET_V', 52); }
}
/* ------------------------------------------------------------------
+14 -1
View File
@@ -40,11 +40,24 @@ function fb_layout_head($title, array $opt = []) {
<link rel="manifest" href="assets/site.webmanifest">
<link rel="stylesheet" href="assets/style.css?v=<?php echo (int)FB_ASSET_V; ?>">
<?php if ($swColors): ?>
<?php /* 按软件覆写主题色:只改这三个变量,其它样式自动跟着变 */ ?>
<?php
/* 按软件覆写主题色。
* --brand-tint-1 / --brand-tint-2 是给下拉项用的两档浅色:
* tint-1(与白混 91%)→ hover
* tint-2(与白混 80%)→ 选中项,比 hover 更深一档,一眼能分开
* 在 PHP 里算好再输出,而不是 CSS 的 color-mix():
* 实测 color-mix 配 var(--brand) 在 Chrome 里解析成透明,规则匹配上却不生效。 */
$tint1 = fb_color_tint($swColors[0], 0.91);
$tint2 = fb_color_tint($swColors[0], 0.80);
$tint3 = fb_color_tint($swColors[0], 0.72); // 选中项 hover 时再深一点
?>
<style>:root{
--brand:<?php echo e($swColors[0]); ?>;
--brand-600:<?php echo e($swColors[1]); ?>;
--brand-soft:<?php echo e($swColors[2]); ?>;
--brand-tint-1:<?php echo e($tint1); ?>;
--brand-tint-2:<?php echo e($tint2); ?>;
--brand-tint-3:<?php echo e($tint3); ?>;
}</style>
<?php endif; ?>
</head>
+25
View File
@@ -253,6 +253,31 @@ function fb_color_variants($hex) {
return [$hex, $dark, $soft];
}
/**
* 按「与白色混合的比例」生成主题色的浅色档位。
*
* 🔴 为什么在 PHP 里算,而不用 CSS 的 color-mix():
* 实测 Chrome 里 `color-mix(in srgb, var(--brand) 9%, #fff)` 配合
* 自定义属性会解析成透明(oklab(0 0 0 / 0))—— 规则匹配上了却不生效。
* 直接在 PHP 把值算好、以 CSS 变量输出最稳,也不依赖浏览器版本。
*
* @param string $hex 主题色
* @param float $ratio 与白色混合的比例(0=原色 1=纯白)
* @return string
*/
function fb_color_tint($hex, $ratio) {
$hex = fb_color_norm($hex);
if ($hex === '') { return ''; }
$r = hexdec(substr($hex, 1, 2));
$g = hexdec(substr($hex, 3, 2));
$b = hexdec(substr($hex, 5, 2));
$ratio = max(0.0, min(1.0, (float)$ratio));
return sprintf('#%02x%02x%02x',
(int)round($r + (255 - $r) * $ratio),
(int)round($g + (255 - $g) * $ratio),
(int)round($b + (255 - $b) * $ratio));
}
/**
* 给某个软件挑一个默认主题色(未配置时用)。
* 按软件的 id 从调色板里取,保证同一站点里不同软件颜色不撞。