Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
11 KiB
11 KiB
TASK · 全站实心按钮配色与禁用态统一(2026-09-28)
基线
origin/staging=b3b5f0e1(2026-09-28)。开工时git fetch origin --prune,以最新origin/staging为基线,实际 SHA 写进 PROGRESS。- 分支
codex/site-button-contrast-20260928,工作树.worktrees/site-button-contrast-20260928。 - 进度记录
docs/tasks/PROGRESS-site-button-contrast-20260928.md。 - 前置:
TASK-chart-types-and-report-buttons-20260928(BUG-1078,报告页局部修复)已部署 staging6a4e312c。本单取代它的局部覆盖,改成全站一处定义。同日其它任务书与本单无文件交集;frontend/src/app/globals.css只动本单列出的规则。
事故实证(Claude 2026-09-28 全站扫描)
方法:TypeScript AST 列出 frontend/src 里全部 213 个 <Button> / <button>,再把 staging 线上实际下发的 CSS(/_next/static/chunks/*.css)装进无头 Chrome,深浅两种主题逐一读计算样式、按叠加后的颜色算对比度。脚本已随本单提交:docs/testing/button-contrast-harness.cjs。
| 样本 | 浅色 文字 / 底 / 对比 | 深色 文字 / 底 / 对比 |
|---|---|---|
<Button> 默认实心 |
#1d1d1f / #a9583e / 3.33 |
#f2f0ea / #d78064 / 2.57 |
<Button> 默认 · 禁用 |
45% 透明 / 1.49 | 45% 透明 / 1.83 |
.button-primary |
#fbfaf7 / #cc785c / 3.14 |
#241f1c / #d78064 / 5.56 |
.button-primary · 禁用 |
45% 透明 / 1.61 | 45% 透明 / 2.20 |
.danger-primary |
#fbfaf7 / #9a2f2f / 7.13 |
#241f1c / #e08573 / 6.04 |
| 输入框发送键 | #fbfaf7 / #cc785c / 3.14 |
#241f1c / #d78064 / 5.56 |
报告页 <Button>(BUG-1078 已修) |
#fbfaf7 / #a9583e / 4.85 |
#f2f0ea / #8f4a33 / 5.77 |
| 描边 / 次要按钮 | 16.12 | 13.30 |
受影响范围:
- 实心
<Button>,渲染为真<button>的共 63 个(渲染为链接<a>的不受影响),其中报告页 2 个已由 BUG-1078 修好,未修 61 个:后台管理 52、点数 / 订阅面板 3、星历 2、生时校正对话 2、输入框发送 / 停止键 2(这两个另有.composer层外规则上色,见下)。日期选择器选中日(calendar.tsx的bg-primary text-primary-foreground,birth-date-picker.tsx用!强行救回了一处)同病。 .button-primary共 30 个:登录 7、首次引导 3、人物档案 3(含 2 个.danger-primary)、首页 2、生时校正各卡 11、兑换码付费墙 2、星盘资料表单 1、首页错误屏 1。- 禁用态:全部 213 个按钮都被
button:disabled { opacity: .45 }整体淡化。 - 其它自定义按钮类(
.button-secondary、会话列表、Tab、chip 等)逐条算过,均 ≥ 4.5。
根因(按符号定位,基线 b3b5f0e1)
frontend/src/app/globals.css顶部元素规则button { color: inherit; }、button:disabled { cursor: default; opacity: .45; }不在任何@layer里。Tailwind v4 的工具类(text-primary-foreground、disabled:opacity-50)都在@layer utilities;层外规则一律压过层内规则,与选择器权重无关。所以<Button>的文字色永远是继承来的正文色:浅色是近黑,深色是近白。Tailwind 预检(preflight)在@layer base里本来就给button设了color: inherit,这条层外规则是重复的。.button-primary与发送键用--color-action-strong(#cc785c)作底,文字用--color-on-dark。深色主题把--color-on-dark翻成#241f1c,于是深色下是深字配珊瑚底,浅色下是白字配浅珊瑚(3.14)。frontend/DESIGN.md「Where the action color appears」写明这是产品曾接受的已知缺口("looks like Claude")。- 两套实心按钮各自取色:
<Button>走--color-primary(=--color-action),.button-primary走--color-action-strong。同一个"主操作"在不同页面是两种颜色。 - BUG-1078 只在报告页作用域内覆盖了颜色(
globals.css里:is(.report-center-message, …) [data-slot="button"]…那一段 +.report-center-generate),根因 1 没动。
决策记录(产品 2026-09-28 拍板)
- D1 全站一种实心主按钮(产品选 A),与报告页 BUG-1078 已上线的配色相同:
- 浅色:底
#a9583e(--color-action)+ 字#fbfaf7,4.85:1;悬停--color-action-hover(#8f4630)。 - 深色:底
#8f4a33(--color-action-on-dark)+ 字#f2f0ea(--color-ink),5.77:1;悬停与报告页同法(向 ink 混 6%)。 - 适用:
<Button>默认变体、.button-primary、输入框发送 / 停止键、日期选择器选中日。
- 浅色:底
- D2 推翻 DESIGN.md 的"已知缺口":
.button-primary不再用#cc785c珊瑚底。代价是登录、首次引导按钮深一档,没那么像 Claude,产品接受。#cc785c在非按钮处照旧:会话选中竖条、焦点环、打字光标、单选圆点、两处头像圆。 - D3 实心按钮禁用态 = 中性灰:底
--color-canvas-strong、字--color-ink-tertiary、不透明(opacity 1)。适用于 D1 的全部实心按钮与.danger-primary。描边、幽灵、次要、图标、chip 等非实心按钮的禁用淡化不在本单范围,保持现状。 - D4 删掉 BUG-1078 的报告页局部覆盖:一处定义、全站生效。报告页观感不变(数值与 D1 相同)。
- D5
.danger-primary启用态保持现在的对比度(浅 7.13、深 6.04):.button-primary改色后它不得被连带改成浅字配浅红,需要时给它单独写文字色。 - D6 不重映射
--color-primary:它还被text-primary用在报告页的加载圈和图标上,深色下改成#8f4a33会让这些图标对比度掉到约 2.3。新增一对只给按钮用的 token(建议名--color-action-fill/--color-on-action-fill,深浅各一组),<Button>默认变体、.button-primary、发送键、日历选中日都引用它。
硬红线
- 修根因:
button { color: inherit; }删掉(preflight 已有),button:disabled那条移进@layer base,或改成不压工具类的写法;不得在各页面再写局部覆盖来绕开。 - 不改
--color-primary/--color-primary-foreground的映射(D6);不改#cc785c的非按钮用途(D2)。 - 非实心按钮的外观与禁用态不变:用 harness 前后对比描边、次要、幽灵的数值,必须完全相同。
.danger-primary两种主题 ≥ 4.5:1。- 每个 D1 实心按钮两种主题 ≥ 4.5:1;禁用态 opacity = 1。
components/ui/button.tsx可以改(上一单的红线只针对报告单),但变体名和 props 不变,调用方零改动。frontend/src/app/page.tsx不碰;/保持○ Static;首屏 gzip ±2%。- 改既有断言写「原值 / 新值 / 原因」(
report-buttons-scope-20260928.test.ts必然要改);测试总数不低于基线。 - 不升级依赖;harness 不进
package.json,只用本机全局 playwright-core + Chrome。
任务分解
T1 根因:层外元素规则
- 处理
globals.css顶部的button { color: inherit; }、button:disabled { … }(见红线 1)。 - 源码合同测试:
globals.css里不存在层外的button { color与层外的button:disabled。 - 验收:harness 显示
<Button>默认变体文字色 =text-primary-foreground解析值;描边 / 次要 / 幽灵数值与基线逐项相同。
T2 按钮专用 token + 两套实心按钮合一
- 新增 D6 的 token 对(
:root、prefers-color-scheme: dark且非data-theme=light、[data-theme=dark]三处,照现有主题写法)。 button.tsx默认变体改用新 token(含 hover),禁用态按 D3。.button-primary、.composer .composer-row-end > button、.composer .composer-stop改用新 token,禁用态按 D3。.danger-primary按 D5 保持对比度,禁用态按 D3。- 日期选择器选中日走新 token,删掉
birth-date-picker.tsx里的!强制补丁(根因修了就不需要)。 - 验收:harness 全表 D1 项两种主题 ≥ 4.5,禁用态 opacity 1、灰底;数值写进 PROGRESS。
T3 删 BUG-1078 局部覆盖
- 删掉报告页作用域的颜色与禁用规则、
.report-center-generate类(generate-personal-report-button.tsx里的 className 一并去掉)。报告导出套餐选中态(.report-export-presets [aria-pressed="true"])是另一回事,保留。 report-buttons-scope-20260928.test.ts改为全站合同,三栏说明。- 验收:报告页 harness 数值与改前相同(4.85 / 5.77,禁用灰)。
T4 文档
frontend/DESIGN.md:「Where the action color appears」删掉"已知缺口"段,改写两级规则(按钮底 =--color-action-fill;#cc785c只留非按钮用途);「Button」一节写 D1–D3。docs/BUG_HISTORY.md:BUG-1079(全站实心按钮文字被层外button { color: inherit }压掉 +.button-primary低对比 + 禁用半透明)。关联 BUG-1078,写明 1078 只修了报告作用域、根因未动,所以同病在其它 60 多处未拦住。CHANGELOG.md一条(Skill 不 bump)。docs/testing/site-button-contrast-20260928.md:真机清单,浅 / 深各走一遍:登录、首次引导、点数与订阅面板、兑换码、人物档案(含删除确认)、星盘资料保存、星历、生时校正卡片、输入框发送 / 停止 / 排队、日期选择器、我的报告导出;每处看"文字清楚、禁用是灰不是淡红"。
让步顺序
- 后台管理页(
components/admin/*)的真机走查可以只抽 3 页,其余靠 harness 与合同测试。 - 日期选择器选中日若牵动
calendar.tsx太多,保留birth-date-picker.tsx的补丁,只在 PROGRESS 说明。
T1、T2 的 <Button> / .button-primary / 禁用灰不让。
开工前置命令
cd /workspace/Jyotisha && git status -sb | head -1
git fetch origin --prune
git worktree add -b codex/site-button-contrast-20260928 .worktrees/site-button-contrast-20260928 origin/staging
cd .worktrees/site-button-contrast-20260928
grep -oE "^## BUG-[0-9]+" docs/BUG_HISTORY.md | sort -t- -k2 -n | tail -1 # 应为 BUG-1078
grep -n "BUG-1078\|button-primary\|opacity: .45" docs/BUG_HISTORY.md | head
cd frontend && export PATH=/exec-daemon:$PATH && npm ci && ./node_modules/.bin/tsc --noEmit && npm run lint && npm test 2>&1 | tail -6 # 记基线与失败名单
npm run build && mkdir -p /tmp/btn-base && cp .next/static/chunks/*.css /tmp/btn-base/ && node ../docs/testing/button-contrast-harness.cjs /tmp/btn-base # 基线数值
harness 只读刚 build 出来的 CSS。09-28 扫描时一份过期的 .next 曾让已上线的修复看起来不存在。
BUG 编号
起点 BUG-1079(开工时核对 docs/BUG_HISTORY.md 最大号为 1078)。
交付
- 代码 + 文档同批一次快进推
git push origin HEAD:staging,核对远端 SHA;门禁绿后核对/api/health的deployment.gitCommit,再用 harness 对 staging 线上 CSS 复测一遍,数值贴进 PROGRESS。 - 不提升
main、不改 workflow。