From 8db38a834dea003b5ca9a40bd9d88131347c4fdb Mon Sep 17 00:00:00 2001 From: laoyang Date: Wed, 4 Nov 2026 19:31:55 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8B=E6=8B=89=E6=A1=86=E6=94=B9=E5=9B=9E?= =?UTF-8?q?=E8=BD=AF=E4=BB=B6=E4=B8=BB=E9=A2=98=E8=89=B2=EF=BC=9B=E4=BF=AE?= =?UTF-8?q?=20color-mix=20=E4=B8=8E=E5=8F=98=E9=87=8F=E9=85=8D=E5=90=88?= =?UTF-8?q?=E5=A4=B1=E6=95=88=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用户:「下拉框的颜色就用那个软件的主题颜色,不行吗?现在怎么还是都是灰的呀? 我感觉用主题颜色就行,挺好看的。」 上一版我判断错了:看到同步日历主题色 #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,否则会误判成"样式失效"。 --- assets/style.css | 61 +++++++++++++++++++++++++++++++++++++---------- lib/bootstrap.php | 2 +- lib/layout.php | 15 +++++++++++- lib/util.php | 25 +++++++++++++++++++ 4 files changed, 88 insertions(+), 15 deletions(-) diff --git a/assets/style.css b/assets/style.css index 4b009e6..e7e67d5 100644 --- a/assets/style.css +++ b/assets/style.css @@ -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; diff --git a/lib/bootstrap.php b/lib/bootstrap.php index f07b501..30b0ea2 100644 --- a/lib/bootstrap.php +++ b/lib/bootstrap.php @@ -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); } } /* ------------------------------------------------------------------ diff --git a/lib/layout.php b/lib/layout.php index a94c41e..4f82f00 100644 --- a/lib/layout.php +++ b/lib/layout.php @@ -40,11 +40,24 @@ function fb_layout_head($title, array $opt = []) { - + diff --git a/lib/util.php b/lib/util.php index 774ea28..7d285d8 100644 --- a/lib/util.php +++ b/lib/util.php @@ -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 从调色板里取,保证同一站点里不同软件颜色不撞。