下拉框改回软件主题色;修 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
+48 -13
View File
@@ -2,6 +2,14 @@
:root{
--fg:#1f2329; --muted:#6b7280; --line:#e5e7eb; --line-strong:#d7dbe0;
--bg:#f5f6f8; --card:#ffffff; --brand:#0057B8; --brand-600:#004a9e; --brand-soft:#e8f0f9;
/* 主题色的两档浅色,供下拉项 hover / 选中使用。
* 有软件时由 layout.php 按该软件主题色覆写;这里给默认蓝色的一套,
* 保证后台、首页这类"无当前软件"的页面也有值可用。
* 为什么不用 CSS color-mix():实测它配 var(--brand) 在 Chrome 里
* 会解析成透明(oklab(0 0 0 / 0)),规则匹配上却不生效。 */
--brand-tint-1:#ecf3fa; /* hover:与白混 91% */
--brand-tint-2:#cfe0f1; /* 选中:与白混 80% */
--brand-tint-3:#b9d1ea; /* 选中+hover:与白混 72% */
/* 顶栏品牌图标:与官网首页同一枚应用图标(内联,离线预览也能显示) */
--icon-mark:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAADsOAAA7DgHMtqGDAAADj0lEQVR4nO1b205TQRTdGB/UB78B0BdfRNA3NUT/QPHMHIgaP0BeMPqoog8mJqDyCfoBImJnDuCFyEWhIGiUegONimkFodYEaqpj9qEEwZbS0zOXXlaykqZNO2uvM9M9Z8/ZABkhysBy9gLhl4Dwh0B5CAj7CZQLo4iaCJtwNRLWDITVZI4tY+CMAOGvtQfnnSGwnWNuLFmBBnYAZU8NCMAvDoLlVGwseCtwAAgLGyDaZ7IZsJ3D6wdP+CEg7Jd+sdIYBytQm+bKOxVAecQAkfJngsV3rolelBXYms/EgdV/jJRTA0SpJeF1K1c/v1OdRwPYxFL8dtc+7WJ00Q5U4/S/rF2INrKLkNzeiqIkYfcBCHujXYg+hgAoixkgRBNZDHL5gU22IxraxsXdkYiYnlsUid9/hGzgGDhWRzAi6tvGXQ05mQAev1jZ2CtGp6JCN0Ymo64WpQZUNvaKSDQuTEE4GhcVXk0AD9PehCu/FsH3UW/LAbL8Aq55U2HfGJNvQOdoRJiKO8GwfAO+zi0KU/Hl+6J8AxIKUp1XoDbpBqTCp9kFsftsf/aDe2TVuX7xeXYhpRYtBrR0TikLfpmt9z6YY8DQu3mx5XiXsuC3nuh2054xBiBwe9rzYkZ0P5dLHGO9P2JtBpiCkgG0NANEQaTBbSe7xdWOyfxYAi2S0uD2Uz35YcCQpDRoXRvLDwNkpMEnb+c9bbu1GWAKSgbQ0gwQUpdAIsW69JoGNzc4oq71mW+32Epuh6dT7MNzTYNY2fUDeIss3YCOYMTXNIjV3NhCwhcDbg8pKInVpymKekmDj17O+hY8gl5XUBTdZDu+TVk/MayqLA7JgxE8jDAFqKX8tKKDEfhn7aaryqi+8p5PhWgOBiwvBzyMwHo8lqRVHY7iWO3DYXfNazscBQ88cyuUMcCmmyFlekC1Acgr7env8fEz1XpA+YDJ88WP31bq+vga39OhBbQMmtwG72p67BJf69IB2gY2haBbgG4C5T+0i9BFwqNQlI/JrnpclrIHxf6gZLN2Ifp4Hg2oKd4ZwKuSzRI8VHzBs1crDRPYWqZbkGragSNrWmb4oHZRysj6/u8lpKy8aJqmsC8yTc9grdtapl2kNMaBsoMZeged/QXbOIl9kRuC5fYQDhRQ8H3uEs8OArvJ6tztovYAckh1lB2FnGEHqt0GI9w6uoaY2GXCYkvt86iRXwDL2bOR0P4Cy8Hrhv+SooQAAAAASUVORK5CYII=");
--ok:#0f9d58; --ok-soft:#e9f7ef; --warn:#b7791f; --warn-soft:#fff8e6;
@@ -941,22 +949,38 @@ select:hover{
}
.sel-btn:hover{border-color:#c3c9d1}
.sel-btn:focus-visible{outline:none; border-color:var(--brand); box-shadow:var(--ctl-shadow-focus)}
.sel-btn.is-open{border-color:var(--brand); box-shadow:var(--ctl-shadow-focus)}
/* 「打开态」样式统一在下方 .sel-btn.is-open 处定义(含主题色底) */
.sel-txt{
flex:1; min-width:0;
overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
/* 未选择任何值时(如「全部状态」)文字用次要色,弱化存在感 */
.sel-btn.is-placeholder .sel-txt{color:var(--muted)}
/* 自绘箭头 */
/* 自绘箭头:默认灰,**打开或有选中值时用主题色** ——
* 让下拉在视觉上跟当前软件一致(用户要的就是这个)。 */
.sel-caret{
width:11px; height:7px; flex:none;
background:currentColor; opacity:.55;
-webkit-mask:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='7' viewBox='0 0 11 7'%3E%3Cpath d='M1 1.2 5.5 5.8 10 1.2' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/contain no-repeat;
mask:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='7' viewBox='0 0 11 7'%3E%3Cpath d='M1 1.2 5.5 5.8 10 1.2' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/contain no-repeat;
transition:transform .16s;
transition:transform .16s, background .12s, opacity .12s;
}
.sel-btn.is-open .sel-caret{transform:rotate(180deg); opacity:.85}
/* 打开时箭头转 180° 并变成主题色 —— 明确"这个下拉是激活的",
* 同时和主题色呼应。 */
.sel-btn.is-open .sel-caret{
transform:rotate(180deg);
background:var(--brand);
opacity:1;
}
/* 打开时按钮整体也染上主题色:
* 浅主题底 + 主题边框,不用再靠外圈光晕强调。 */
.sel-btn.is-open{
border-color:var(--brand);
background:var(--brand-soft);
color:var(--brand-600);
box-shadow:var(--ctl-shadow-focus);
}
.sel-btn.is-open .sel-txt{color:var(--brand-600); font-weight:600}
/* 浮层:fixed 定位,不被任何 overflow 容器裁切。
* 用白底 + 细边框 + 柔和阴影,而不是浏览器默认的灰块。 */
@@ -988,16 +1012,27 @@ select:hover{
}
.sel-item-txt{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis}
/* hover / 键盘高亮:中性浅灰,**不要用 --brand-soft**。
* 🔴 踩过:最初选中项用 var(--brand-soft),但那个变量会被软件主题色覆盖 ——
* 同步日历是砖红色,--brand-soft 就成了 #ffe8e9(粉红),
* 下拉里一片粉,很难看。下拉是**工具性控件**,不该跟着软件换色,
* 统一用中性色才耐看。 */
.sel-item:hover, .sel-item.is-active{background:#f1f3f6; color:var(--fg)}
/* hover / 键盘高亮:主题色最浅一档。
* 用户 2026-11-04:「下拉框就用那个软件的主题颜色,挺好看的。」
* (上一版我误判成中性灰,已改回主题色系。)
* ⚠️ 用 PHP 算好输出的 --brand-tint-1,不用 color-mix():
* 实测 color-mix(in srgb, var(--brand) 9%, #fff) 在此环境解析成透明。 */
.sel-item:hover, .sel-item.is-active{
background:var(--brand-tint-1);
color:var(--brand-600);
}
/* 选中项:浅灰蓝底 + 深色文字 + 右侧对勾(不依赖主题色) */
.sel-item.on{background:#eef1f5; color:var(--fg); font-weight:600}
.sel-item.on:hover, .sel-item.on.is-active{background:#e6eaf0; color:var(--fg)}
/* 选中项:比 hover 深一档 + 主题色文字 + 右侧对勾,
* 一眼看出当前选的是哪个,也让"我在哪个软件的反馈系统里"更明确。 */
.sel-item.on{
background:var(--brand-tint-2);
color:var(--brand-600);
font-weight:600;
}
.sel-item.on:hover, .sel-item.on.is-active{
background:var(--brand-tint-3);
color:var(--brand-600);
}
.sel-item-ck{
width:13px; height:10px; flex:none;
background:currentColor;