前端改造:设计令牌 + 卡片层级 + 图表可读性 + 类型色收口 + 窄屏导航
先出方案(frontend-plan-2026-10-09.md)再动手,四批按顺序落地。方法上先存基线、再用同一份 探针在改动前后逐值 diff —— 这批里有 6 处问题只有「量」才看得见,看截图全是正常的。 A 设计令牌(app.css 为主) - 字阶收敛到 6 档 --fs-xs/sm/md/lg/xl/2xl = 11/13/15/21/26/34px。原来 app.css 有 19 种字号、 模板里另有 54 处内联字号,光 12~15px 之间就挤了 4 档 —— 层级挤不出来,只能靠加粗硬顶。 - 两个「字外档」不是漏的:--fs-control: 16px(窄屏表单控件必须 ≥16px,否则 iOS 聚焦放大整页, 属功能约束);--glyph-*(✕/箭头/空态图标按控件尺寸定,硬塞进字阶只会把按钮撑坏)。 - 字重收敛到 400/500/600(删掉 650 与 700)。 - 圆角 4 档 --r-*、阴影 3 档 --sh-1/2/3(暗色整套覆盖)、间距 --sp-1..5、 卡片内边距单列 --card-pad(与折叠卡片标题行的负 margin 绑在一起,改一个即改两处)。 - 门禁 TestNoBareFontSizePx:静态扫 app.css 与全部模板,出现 font-size: <数字>px 即红。 B 卡片分主次 - .card--hero / .card(默认)/ .card--quiet 三档。quiet 走「页面底色 + 细边 + 无阴影」—— 第一版拿 --bg-2 当底色,实测它与页面底 #f6f7f8 只差 4/255,看不出边界、像破了个洞。 - 首屏 KPI 从「4×2 等重白盒」改成 .kpi-lead(主数 + 一行上下文)+ 5 个常规指标,8 个数字一个没少。 C 图表说人话 - 月度分布:柱底加基线;峰值柱不透明拉满、柱顶标次数(.pv),副标题里不再重复写「最高 N 次」。 - 一天中的分布:把「0/6/12/18 四个数字」换成 6 小时一段的标尺(深夜/上午/下午/晚上), 用同一套 24 列网格,段边界与柱子严格对齐。 - 首页月度图同样加峰值锚点(给 HomeData 补 MaxMonthly,与统计页同口径 maxOf)。 - 空态没动:查下来已经统一(8 页共用 emptystate、局部走 .empty)。 D1 类型色语义化(结论与计划不同,按实测改了) - 先算对比度:白底上 yellow 1.87 / mint 2.12 / orange 2.20 / green 2.22 / cyan 2.54 / teal 2.57, 6 个色连图形对象 3:1 都到不了;暗底只有 indigo 2.90 不够。 - 所以**没有**把类型色用到 chips / 表格类型列 / KPI 强调 —— 那几处要的是文字色,只会更难读。 这也解释了全站为什么一直只用 8px 小圆点做身份标记。浅色那 6 个色一个没动: 它们是手机端与地图上的同一套身份色,改暗会破坏对应关系。 - 实际做的:色值收口成 --cat-* / --cat-*-soft(26 个变量);模板 colorof → csscolor / csssoft(19 处); 暗色只提亮 indigo(2.90 → 3.55:1);colorOf 成了死代码,删掉。 - ⚠️ 返回值必须是 template.CSS:html/template 的 CSS 过滤器不认识 var(),普通 string 会被静默 换成 ZgotmplZ —— 页面上所有圆点当场变透明,而且不报错、模板测试照过。挂了它等于关掉那道过滤, 所以数据侧色值先过严格校验(只有 # + 6 位 hex 放行),否则 #"><img… 能逃出 style 属性。 守卫 TestCSSColorSurvivesTemplateSanitizer 把两个方向都钉住(做过变异验证)。 D2 窄屏导航 - 改前 ≤620px 靠横向滚动兜底:390 溢 63px、320 溢 133px,「统计」被切成半个字紧贴后面的按钮, 渐隐提示实际看不出来。现在链接本体抽成 {{define "navitems"}} 渲染两遍:桌面 .nav-links 平铺、 窄屏 .nav-menu(原生 <details>,不靠 JS 也能开合);JS 只补点外面 / Esc / 点链接后收起。 - ⚠️ 顶栏 --z-nav 抬到 1200:菜单是 .nav 的子元素、自己抬不动层叠上下文,不抬就会被地图页的 --z-map-overlay(1100) 盖住。已在 /map 上用 elementFromPoint 实测。 - 守卫 TestNarrowNavCollapsesToMenu 钉「CSS 两半 + 模板两个类 + 渲染两遍」的成对关系。 途中发现并一并修掉的(都只有量 DOM 才看得见) - Leaflet 的 .leaflet-container 字号是 0.75rem、跟着根字号漂:根 14 → 13px 后地图署名/比例尺 掉到 9.8px(低于本站 11px 下限)、弹窗正文也跟着缩。已按自己的字阶钉死。 - h1..h4 原来只设了字重与 margin、没设字号,靠浏览器默认的 2em/1.5em/1.17em —— 同样跟着根字号漂: /stats 那两个 h2 从 21px 变成 19.5px,比同页卡片标题大一圈。已显式给出字号。 - <b>/<strong> 浏览器默认 700,比全站最高层级(标题 600)还重,已钉成 600。 回归 - ./scripts/verify.sh:PASS=348 FAIL=0 SKIP=0 - internal/fog 加 -race:PASS=22 FAIL=0 SKIP=0 - JS 单测 34/34 - 移动端 320 / 390 溢出全 0(改前 /admin 在 320 还溢 34px);桌面 1440 与改前一致(−15 是滚动条宽) - 全站 7 个页面都没有低于 11px 的文字 说明:A/B 与 C/D 本想拆两笔提交,但 app.css / layout.html / view.go 里两批改动交织,按文件拆不开、 按 hunk 拆又容易做出「中间那笔编译不过」的历史,所以合成一笔、在消息里分段。
This commit is contained in:
@@ -91,3 +91,96 @@ at <.Settings.TrackEnabled>: can't evaluate field TrackEnabled in type setting.S
|
||||
- 验收:官方 `./scripts/verify.sh` → **PASS=346 FAIL=0 SKIP=0**(改动前那次全量;
|
||||
之后只动了这一个模板文案,重跑了全部模板门禁与 `TestSmokeRender*`,全绿)。
|
||||
|
||||
## 提交 + 前端现代化方案
|
||||
|
||||
**提交**:`d4e4257`「启动模板自检 + 站长导航放行 + 统计脚本关口收紧」(12 文件,+564/−75)。
|
||||
|
||||
⚠️ **`shots/` 里的截图是旧状态,做视觉判断前必须现场重截**:`mobile-home.png` 还显示顶栏
|
||||
折成 3 行、右按钮竖排,实测现在 390 下品牌名只留 🐾、按钮「后台」、`navH=51` 且不溢出。
|
||||
差点拿旧图当现状写进方案。
|
||||
|
||||
**现状实测(CDP,真实视口)**:
|
||||
- 卡片:17 个盒子(`.card`/`.kpi`/`.filters-card`)**只有 2 种样式指纹** ⇒ 层级扁平。
|
||||
- 字阶 8 档(10/12/13/14/15/18/21/23),10–15px 挤了 5 档;字重 400/500/600/**650**。
|
||||
- 正文色只有 4 种;类型色 10 种只用在圆点与柱子,没进界面语义层。
|
||||
- 站长导航 `scrollWidth=277`:430→254(溢 23)、390→214(溢 63)、320→144(溢 133);
|
||||
390 下「统计」被切成半个字紧贴「后台」,`.overflow-right` 的渐隐看不见。
|
||||
- 已有优点别改坏:KPI 已是 `tabular-nums`、`--text-3` 按 AA 调过、暗色模式已有 3 段 media。
|
||||
|
||||
**产出**:`frontend-plan-2026-10-09.md`(仓库根,与 `audit-2026-09-21.md` 并列)。
|
||||
四批:A 设计令牌收敛(字阶砍到 6 档、字重 3 档、间距/圆角/阴影令牌)→ B 卡片分 hero/常规/次级
|
||||
+ 首屏 1 个大数 → C 手写图表加基线/峰值/轴标(不上图表库)→ D 类型色语义化 + 窄屏导航。
|
||||
**明确不做**:前端框架/构建链、图表库、信息架构重构。建议先做 A+B(约 1.5 天,纯 CSS + 少量 class)。
|
||||
方案**未改任何代码**,等选批次。
|
||||
|
||||
---
|
||||
|
||||
## 落地:A + B 批次(用户选了「先按 A-B 去做」)
|
||||
|
||||
**做法**:先跑基线存档(`ab.js` 探针 + `audit/run_all.py --mobile 390` / `--overflow 1440`),
|
||||
再改,再用同一份探针跑一遍逐值 diff。CSS 改动量 187+/150−,另有 19 个模板共 54 处内联字号并档。
|
||||
|
||||
**关键结果**(同一探针,改动前 → 后):
|
||||
- `/` 的 (字号,字重) 组合 390:**13 → 10**、1440:**15 → 10**;`/places` 10 → **5**;
|
||||
`/timeline` 10 → **6**;`/stats` 15 → **9**;`/admin/settings` 10 → **7**。
|
||||
- 最小字号到处都 ≥11px(原来有 10 / 10.5px)。
|
||||
- 卡片样式档:`/` 2 → **3**,`/admin/settings` 1 → **2**。
|
||||
- 溢出:移动端审计**逐值一致**;桌面 1440 唯一差异是 `/map` 露外元素 9 → 8。
|
||||
- 验收 `./scripts/verify.sh`:**PASS=347 FAIL=0 SKIP=0**。
|
||||
|
||||
**踩到的四处**(都只有「量 DOM 的 (字号,字重) 组合」才看得见,截图上看都正常):
|
||||
1. **Leaflet 字号跟着根字号漂**:vendor `.leaflet-container { font-size: .75rem }`,
|
||||
根 14 → 13px 后地图署名/比例尺掉到 **9.8px**、弹窗正文也跟着缩。
|
||||
已在 app.css 钉死(容器 `--fs-sm`、署名/比例尺 `--fs-xs`)。
|
||||
2. **项目自带的静态守卫抓到我**:`TestNavLinksNarrowRuleHasNoDeadPadding` 写死了 `font-size: 13px`,
|
||||
并档后它红了。守卫是对的,改判据为「钉规则还在、且设了字号」;另补 `TestNoBareFontSizePx`
|
||||
(静态扫 app.css + 模板禁裸 px 字号,做过变异验证)。
|
||||
3. **`h1..h4` 从没设过字号**(原来只有字重与 margin),靠浏览器默认 `2em/1.5em/1.17em` ⇒ 也跟着根字号漂:
|
||||
根 14 → 13px 后,`/stats` 里没被 `.card > h2` 命中的两个 h2 从 21px 变成 19.5px,比同页卡片标题(15px)大一圈。
|
||||
已显式给出 h1/h2/h3 字号,实测 12 个 h2 统一 `15px/600`。
|
||||
4. **`<b>/<strong>` 浏览器默认 700**,比全站最高层级(标题 600)还重 ⇒ 已钉成 600。
|
||||
|
||||
**教训(已写进 details 四十二)**:quiet 卡片第一版用 `--bg-2`(#fafbfb),
|
||||
与页面底 #f6f7f8 只差 4/255 ⇒ 实测看不出边界、像「破了个洞」。**配色差异必须量,不能凭「应该能看出来」。**
|
||||
|
||||
**运维提醒**:测试库跑到 180MB / 21 万死元组时 `verify.sh` 会从 8 分钟拖到 12 分钟以上
|
||||
(脚本 200MB 才自动 VACUUM);手动 `VACUUM (ANALYZE)` 后回到 ~10 分钟、137MB / 0 死元组。
|
||||
|
||||
**发现未修**:7 个模板工作区里是 CRLF,而 `.gitattributes` 要求 `eol=lf`
|
||||
(`admin/index.html`、`admin/login.html`、`admin/twofa-login.html`、`admin/twofa.html`、
|
||||
`map.html`、`places.html`、`timeline.html`)。本批按字节替换保住了各自行尾、diff 无行尾噪声,
|
||||
要不要统一另开一次清理。
|
||||
|
||||
---
|
||||
|
||||
## 落地:C + D 批次(用户选了「C和D继续做」)
|
||||
|
||||
**C 图表**:月度分布加基线 + 峰值柱标次数(`.pv`,副标题不再重复写「最高 N 次」);
|
||||
一天中的分布把「0/6/12/18 四个数字」换成 **6 小时一段的标尺**(深夜/上午/下午/晚上),
|
||||
用**同一套 24 列 grid** 保证段边界与柱子严格对齐;首页月度图同样加峰值(给 `HomeData` 补了 `MaxMonthly`)。
|
||||
**空态那条划掉了** —— 查下来已经统一(8 页共用 `emptystate`、局部走 `.empty`)。
|
||||
|
||||
**D1 类型色**:先算对比度,结论推翻了原计划 ——
|
||||
|
||||
- 白底上 6 个色低于图形 3:1(yellow 1.87 / mint 2.12 / orange 2.20 / green 2.22 / cyan 2.54 / teal 2.57)
|
||||
- 暗底只有 indigo 2.90 不够
|
||||
|
||||
所以**没有**把类型色做成 chips / 表格类型列 / KPI 强调(那几处要的是文字色,会更难读)——
|
||||
这恰好解释了全站为什么一直只用 8px 小圆点做标记。浅色 6 个色一个没动(是手机端/地图的同一套身份色)。
|
||||
实际做了:色值收口成 `--cat-*` + `--cat-*-soft`(26 个变量)、模板 `colorof` → `csscolor`/`csssoft`(19 处)、
|
||||
暗色只提亮 indigo。`colorOf` 已成死代码,删掉。
|
||||
|
||||
⚠️ **踩到 `ZgotmplZ`**:`html/template` 的 CSS 过滤器不认识 `var()`,函数返回普通 string 会被替换成
|
||||
`ZgotmplZ`,页面上所有圆点当场变透明、**且不报错、模板测试照过**。
|
||||
必须返回 `template.CSS`;而挂了它等于关掉过滤,所以数据侧色值先过严格校验(只有 `#`+6 位 hex 放行)。
|
||||
已加守卫 `TestCSSColorSurvivesTemplateSanitizer`(两个方向都钉,做过变异验证)。
|
||||
|
||||
**D2 窄屏导航**:≤620px 整行收进 `.nav-menu`(原生 `<details>`,JS 只补点外面/Esc/点链接后收起)。
|
||||
⚠️ 顶栏 z-index 抬到 `--z-nav: 1200`(必须高于地图浮层 1100,否则展开的菜单被筛选面板盖住),
|
||||
已在 `/map` 用 `elementFromPoint` 实测。改前 390 溢 63px、320 溢 133px(「统计」被切半个字)。
|
||||
|
||||
**回归**:`verify.sh` **PASS=348 FAIL=0 SKIP=0**;320/390 溢出**全 0**(改前 `/admin` 在 320 还溢 34px);
|
||||
桌面 1440 与改前一致;**7 个页面都没有低于 11px 的文字**;暗色下菜单/类型色/阴影均按暗色变量生效。
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -945,3 +945,80 @@ HTML,一行里必然带 `</script>`,一拒就把正常用法挡死了(我
|
||||
`dist/rond-linux-amd64`。相关技能(`rond-web-verify`)与 details 十八已同步改掉
|
||||
`bin/rond.exe` 的写法。
|
||||
|
||||
## 四十二、前端设计令牌(A/B 批次,2026-10-09)
|
||||
|
||||
完整方案与实测数据见仓库根 `frontend-plan-2026-10-09.md`。这里只记**以后改前端必须守的规矩**。
|
||||
|
||||
### 字阶 / 圆角 / 阴影一律走令牌,别写 px
|
||||
|
||||
- 文本 6 档:`--fs-xs/sm/md/lg/xl/2xl` = 11 / 13 / 15 / 21 / 26 / 34px。
|
||||
- `--fs-control: 16px`:**窄屏表单控件必须 ≥16px**(iOS 聚焦 <16px 会把整页放大)。这是功能约束,
|
||||
所以它独立于字阶;窄屏媒体查询里用 `--field-fs` 覆盖。**别把它并进字阶。**
|
||||
- `--glyph-*` 6 档:✕ / 箭头 / 空态图标 / 表情的字号。**字形不是文字层级**,按控件尺寸定;
|
||||
硬塞进字阶(比如把 22px 的 ✕ 提到 26px)只会把按钮撑坏。
|
||||
- 圆角 `--r-xs/sm/md/lg` = 3 / 6 / 8 / 12px。`50%` 与 `999px` 是形状(圆 / 胶囊),不算圆角档。
|
||||
- 阴影 `--sh-1/2/3`:⚠️ **暗色模式必须整套覆盖**(原来只覆盖一个 `--shadow`,拆档后漏一个就会
|
||||
在暗色下用错档)。
|
||||
- 间距 `--sp-1..5` 本批**只迁移了卡片内边距这类主节奏**,其余没做全量替换。
|
||||
- `--card-pad` 与折叠卡片标题行的负 margin 绑在一起(`calc(var(--card-pad) * -1)`),改一个即改两处。
|
||||
|
||||
**门禁** `TestNoBareFontSizePx`:静态扫 app.css 与全部模板,出现 `font-size: <数字>px` 就红。
|
||||
|
||||
### 卡片三档
|
||||
|
||||
`.card--hero`(首屏地图 / 主数区)/ `.card`(默认)/ `.card--quiet`(只读说明)。
|
||||
⚠️ quiet **别拿 `--bg-2` 当底色**:它与页面底 `--bg`(#f6f7f8) 只差 4/255,实测看不出边界,
|
||||
卡片会像「破了个洞」而不是「轻了一档」。要「页面底色 + 保留细边 + 无阴影」。
|
||||
|
||||
首屏主数用 `.kpi-lead`(不是 `.kpi`):主数 + 一行上下文 + 左侧 3px 主色条。
|
||||
|
||||
### ⚠️ 改根字号会带动 vendor 库与「没设字号的默认标签」
|
||||
|
||||
`html, body` 的 font-size 一改,至少三处会跟着漂:
|
||||
|
||||
1. **Leaflet**:vendor 里 `.leaflet-container { font-size: 0.75rem }` 是**相对根字号**的,
|
||||
根从 14 → 13px 后地图署名/比例尺掉到 **9.8px**、弹窗正文也跟着缩。
|
||||
app.css 里已钉死(容器 `--fs-sm`、署名/比例尺 `--fs-xs`)。
|
||||
2. **`h1..h4`**:app.css 原来只给它们设了字重与 margin、**没设字号**,于是靠浏览器默认的
|
||||
2em / 1.5em / 1.17em —— 同样跟着根字号漂。已显式给出 h1/h2/h3。
|
||||
3. **`<b> / <strong>`**:浏览器默认 bold(700),比全站最高层级(标题 600)还重。已钉成 600。
|
||||
|
||||
判据:**量 DOM 的 (字号,字重) 组合**。只看截图不会发现这三处(页面「看着正常」,
|
||||
只是有点不齐)。其它 rem/em 的 vendor 样式同理要查。
|
||||
|
||||
## 四十三、图表 / 类型色 / 窄屏导航(C、D 批次,2026-10-09)
|
||||
|
||||
### 图表(手写 .cols / .bars,不引图表库)
|
||||
|
||||
- `.cols` 有基线(`border-bottom`)与 `padding-top: 16px` —— 后者是给峰值柱顶上那个数字(`.pv`)留的位置,
|
||||
改高度时别把 padding 弄丢(`height` 走 border-box,内容区才是柱子的 100% 基准)。
|
||||
- 峰值柱:模板里 `{{if eq .Count $.MaxMonthly}} peak{{end}}`,柱顶标次数;副标题里就不再重复写「最高 N 次」。
|
||||
- `.cols-band` 是「6 小时一段」的标尺,**必须用 24 列 grid**(不是 `flex: 6`),否则段边界与柱子对不齐。
|
||||
它取代了原来那行只有一个数字的坐标轴。
|
||||
- 首页的月度图峰值靠 `HomeData.MaxMonthly`(与统计页同口径 `maxOf`),别只改一边。
|
||||
|
||||
### 类型色:只在 CSS 变量里用,别当文字色
|
||||
|
||||
- 模板用 `csscolor` / `csssoft`(`colorof` 已删)。
|
||||
⚠️ 这两个函数**必须返回 `template.CSS`**:`html/template` 的 CSS 过滤器不认识 `var()`,
|
||||
返回普通 string 会被换成 **`ZgotmplZ`** —— 页面上所有圆点当场变透明,而且不报错、模板测试照过(踩过)。
|
||||
守卫 `TestCSSColorSurvivesTemplateSanitizer`。
|
||||
- 但挂了 `template.CSS` 就等于关掉那道过滤,所以**数据侧色值必须先过严格校验**(只有 `#` + 6 位十六进制放行),
|
||||
否则 `#"><img…` 能直接逃出 style 属性。
|
||||
- ⚠️ **这套色连图形对象 3:1 都到不了**:白底上 yellow 1.87、mint 2.12、orange 2.20、green 2.22、
|
||||
cyan 2.54、teal 2.57。所以它们**只能当身份标记(圆点 / 柱条),绝不能当文字色或承载唯一信息的图形**。
|
||||
实测过、别再被「做成彩色标签更好看」带走。
|
||||
- 浅色那 6 个色**不要改暗**:它们是手机端与地图上的同一套身份色,改暗会破坏对应关系。
|
||||
- 地图那份调色板(`rond-map.js` 的 `APPLE`)**故意独立**:瓦片在暗色下仍是浅色,标记要用浅色底那套值。
|
||||
- 暗色只提亮了 `--cat-indigo`(2.90 → 3.55:1),其余一律不动。
|
||||
|
||||
### 窄屏导航(≤620px)
|
||||
|
||||
- 链接本体是 `{{define "navitems"}}`,渲染两遍:桌面 `.nav-links` 平铺、窄屏 `.nav-menu`(原生 `<details>`,
|
||||
不靠 JS 也能开合;JS 只补点外面 / Esc / 点链接后收起)。
|
||||
守卫 `TestNarrowNavCollapsesToMenu` 钉「CSS 两半 + 模板两个类 + 渲染两遍」的成对关系。
|
||||
- ⚠️ 顶栏 `--z-nav: 1200`,**必须高于 `--z-map-overlay`(1100)**:菜单是 `.nav` 的子元素、
|
||||
自己抬不动层叠上下文,不抬就会被地图的筛选面板盖住(`/map` 上用 `elementFromPoint` 实测验证过)。
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
照 `place.html` 投票区与 `rond-map.js` 气泡的写法。门禁 `TestVisitorPagesUseThirdPersonCopy`
|
||||
(以访客 ctx 渲染 `/`、`/stats`、`/report` 逐个断言禁用词,并确认站长那份仍说「我的」)。
|
||||
- 改 Go 必须重启;模板/CSS/JS 只在 `debug=true` 热加载(`AssetV` 启动哈希)。⚠️ **新模板+旧二进制**=「渲染到一半仍 200」;启动自检 `smokeRender` 会拒启(四十一)。
|
||||
- 字阶/圆角/阴影**只走令牌**,裸 `font-size: 13px` 有静态守卫 `TestNoBareFontSizePx`;卡片三档 `.card--hero/--quiet`。⚠️ 改**根字号**要查 Leaflet(`.75rem` 会跟着漂),(四十二)。
|
||||
- 类型色走 `csscolor/csssoft`(**必须返回 `template.CSS`**,否则 `var()` 被换成 `ZgotmplZ` 且不报错);这套色连 3:1 都不到,**只能当圆点标记、别当文字色**。窄屏导航收进 `.nav-menu`,顶栏 `--z-nav` 必须高于地图浮层(四十三)。
|
||||
- 拼查询串走返回 `template.URL` 的方法(`PlaceLink`/`EditPlaceLink`/`MapLink`/`EditLink`),勿手工转义。
|
||||
- 窄屏覆盖写 `app.css` **末尾那块**;宽表堆叠类名**成对** `class="tb tb-stack"`;触控 44px。`tb_stack_test.go`
|
||||
- 加表格列:`PlaceCols`/`scanPlace` **成对**、新列追加最后;CJK 挤换行只抬该表 `min-width`。
|
||||
|
||||
Reference in New Issue
Block a user