Files
PolyWeather/docs/frontend-ui-design-review.md

17 KiB
Raw Permalink Blame History

PolyWeather Frontend UI 设计审查报告

审查日期:2026-05-10 | 审查范围:frontend/ 全部组件、样式、布局

整体评价

前端设计系统有扎实的基础 — 完善的 CSS 自定义属性 token 体系、不错的暗色模式、合理的排版层级、以及语义化的颜色编码。但存在一些工程性债务需要关注。

最突出的 5 个问题:

  1. !important 在浅色主题中泛滥(~960 行),维护成本极高
  2. font-weight: 760/850/950 等无效值在 CSS 中大量使用
  3. Geist 字体声明但从未加载,始终 fallback 到 Inter
  4. 键盘导航和 focus-visible 样式缺失
  5. 14 个不同的响应式断点值,无统一体系

一、设计系统 & Token 体系

优点

  1. 完整的 CSS 自定义属性体系 (globals.css:9-93):拥有从背景色阶、文字色阶、语义色、阴影、间距、圆角、毛玻璃到动效的完整 token 体系,覆盖面广。

  2. 4px 间距网格:从 --space-1: 4px--space-12: 48px,提供了系统化的间距基础。

  3. 三层毛玻璃系统--glass-blur-1/2/3 + --glass-opacity-1/2/3 的组合创造视觉深度层次,在暗色背景下效果出色。

  4. Tailwind 桥接tailwind.config.ts 提供了 pw-bg-*pw-text-*pw-accent-* 等语义化 utility class,兼顾了设计 token 的语义化和 Tailwind 的效率。

问题

  1. "Fintech 3-Color" 名不副实 (globals.css:25-27)

    --color-accent-primary: #4DA3FF;    /* 蓝 */
    --color-accent-secondary: #4DA3FF;  /* 同上 — 完全一样 */
    --color-accent-tertiary: #93C5FD;   /* 浅蓝 */
    

    primary 和 secondary 是同一个颜色,实际只有 2 种不同色值。"3-Color" 声明具有误导性。

  2. Token 未充分利用:大量 CSS Module 中硬编码了颜色值(如 #4DA3FF#E6EDF3rgba(77, 163, 255, ...))而不是引用 CSS 变量。例如 ScanTerminalCard.module.css 中几乎每一行都是硬编码色值。

  3. shadcn/ui HSL token 遗留 (globals.css:95-106):保留了 shadcn 的 HSL token 但几乎未被使用,增加了 token 体系的认知负担。


二、布局 & 响应式

优点

  1. Scan Terminal 的 CSS Grid 布局 (ScanTerminal.module.css:524-537)grid-template-columns: minmax(0, 1fr) minmax(380px, 420px) 的 2 列布局干净、现代。

  2. 毛玻璃面板系统:所有主面板都有 22px border-radiusbackdrop-filter: blur(14px)、渐变背景和微妙的阴影,视觉统一。

  3. Sticky detail rail:右侧面板 position: sticky; top: 16px; height: calc(100vh - 32px) 保证了用户滚动时详情始终可见。

问题

  1. 两套布局系统并存

    • 旧版 "Home Intelligence" 使用 absolute positioning 定位 header/sidebar/map/panel
    • 新版 "Scan Terminal" 使用 CSS Grid
    • 两套 CSS Module 都在 ScanTerminalDashboard.tsx 中被 import 合并,增加了复杂度
  2. 断点碎片化严重:系统使用了 12+ 个不同断点值 (1680, 1480, 1360, 1240, 1100, 1020, 900, 820, 768, 720, 640, 600, 560, 520),没有统一的体系。同一个 tablet 过渡在一些模块用 768px,在另一些用 720px。

  3. Map View 中的 absolute positioning (DashboardShell.module.css):使用 top/right/bottom/left 绝对定位来排列面板,脆弱且难以维护。


三、色彩 & 对比度

优点

  1. 暗色模式基础扎实#0B1220 的深邃底色配合三层 radial gradient 营造了深度感和科技感。

  2. 语义色系统清晰success/green、warning/amber、danger/red 的映射关系明确。

  3. 渐变运用得当body 背景的三层 radial gradient(绿/紫/青)创造了微妙的大气光感。

问题

  1. 文字对比度偏低

    • 静音文字 #6B7A90#0B1220 上的对比度约为 4.6:1,刚好达到 WCAG AA 标准但仍偏暗
    • 大量 10-11px 的辅助文字使用 #6B7A90,可读性不足
  2. Accent Color 视觉突出度#4DA3FF(蓝色)在暗色背景上的人眼敏感度不如 #00E0A4(青绿色),但前者被用作主要强调色。

  3. 语义色 class 命名不一致accent-green class 实际渲染为 #4DA3FF(蓝色),"green" 命名的 class 显示蓝色。


四、字体排印

优点

  1. 字体选择合理Inter(正文) + JetBrains Mono(数据/代码) 是 fintech/数据密集类产品的标准选择。

  2. tabular-nums 广泛使用:几乎所有温度数值都设置了 font-variant-numeric: tabular-nums,保证了数字对齐。

  3. 层级明确:从 10px 的 kicker 到 56px 的 hero temperature,形成了清晰的视觉层级。

问题

  1. Geist 字体声明但未加载 (layout.tsx:35-37)

    • globals.css 声明了 --font-display: "Geist", "Inter", ...
    • 但 HTML 中只加载了 Inter 和 JetBrains MonoGeist 永远不会生效
  2. 非标准 font-weight 值泛滥

    • font-weight: 760850860880900950 在 CSS 中大量出现
    • Inter 字体只支持 300/400/500/600/700/800
    • 非标准 weight 会被浏览器取整到最近支持值,视觉不可预测
    • 例如 font-weight: 950 在 Inter 上实际渲染为 800
  3. 字体大小偏小:大量 UI 文字使用 10-11px,在高分辨率屏幕上可读性差。

  4. 大写字母过多kicker/overline/chip 几乎全部使用 text-transform: uppercase + letter-spacing: 0.08em,降低了中文/双语场景下的可读性。


五、组件设计

优点

  1. City Decision Card 视觉层次优秀 (ScanTerminalCard.module.css):hero 区的渐变背景、蓝色左边框选中态、决策 band 的色彩编码(warm=red 边框、cold=green 边框、watch=amber 边框),信息密度高但不杂乱。

  2. Status Tags 色彩编码清晰green/blue/amber/red/muted 五种 tag 变体覆盖了数据状态的所有场景。

  3. 双卡预测对比 (AI vs DEB):青色渐变卡 vs 蓝色边框卡的视觉区分让用户能一眼区分 AI 预测和模型预测。

  4. Decision Band 语义化warm(red) = 看涨、cold(green) = 看跌、watch(amber) = 待观察,视觉编码与交易语义对齐。

问题

  1. Topbar 设计过于简单:28px 标题 + 几个按钮,缺乏品牌标识(Logo)和视觉焦点。

  2. Tab 下划线指示器不够明显2px 高度 + opacity: 0.8 的蓝色下划线容易被忽略。

  3. 按钮层级不够清晰.scan-primary-button(蓝紫渐变)、.scan-ai-button(青绿渐变)、.scan-city-icon-button(蓝色边框半透明)、.scan-theme-button(无边框无背景)四种视觉权重混在一起,用户难以判断优先级。

  4. 空状态/加载状态设计不一致

    • 地图加载有精美的云/雷达/热力动画
    • Scan terminal 加载是简单的脉冲 placeholder
    • 空状态是一个简单的文字居中块
    • 缺乏统一的 loading/empty/error 设计规范
  5. Mobile Decision Card 采用 <details> 元素:原生 <details>/<summary> 样式控制有限、动画困难,与桌面端的自定义折叠按钮体验不一致。


六、深色/浅色主题

优点

  1. 浅色模式覆盖全面ScanTerminalLightTheme.module.css 约 960 行,覆盖了 scan terminal 的所有元素。

  2. localStorage 持久化:主题选择保存在 polyweather_scan_theme 中,刷新不丢失。

  3. 浅色配色方案合理:从深色 #0B1220 到浅色 #F7F9FC → #EEF2F7 的映射关系合理。

问题

  1. !important 严重滥用 (ScanTerminalLightTheme.module.css)

    • 几乎每条浅色规则都使用了 !important
    • 这是 specificity war 的症状,维护成本极高
    • 多处出现 !important 叠加
  2. 浅色主题分散在 8+ 个文件中:缺乏集中管理,修改一个颜色需要跨多个文件搜索。

  3. 浅色模式地图图块滤镜处理Leaflet tile 滤镜切换可能影响其他 overlay 的浅色适配。


七、动效 & 过渡

优点

  1. Cubic-bezier 缓动选择正确(0.4, 0, 0.2, 1) (Material standard) + (0.16, 1, 0.3, 1) (spring-like) 的组合符合现代 UI 动效标准。

  2. 入场动画有层次detail panel 从右侧滑入 (400ms)、opportunity strip 有 120ms 延迟。

  3. Hover 微交互:按钮 translateY(-1px)、卡片 scale(1.002)、边框颜色过渡等微交互提升了操作反馈感。

问题

  1. @keyframes spin 重复定义 4 次:在 DashboardShell.module.cssDashboardModalGuide.module.cssDocsLayout.module.cssDashboardMap.module.css 中各自定义了一次完全相同的 spin 动画。

  2. Loading 动画风格不统一DashboardMap 有复杂的 weather-themed 动画(radar swipe、cloud drift、thermal bars、wind shift),而 scan terminal 只有简单的扫光 placeholder。

  3. 缺少 prefers-reduced-motion 支持:没有任何 @media (prefers-reduced-motion: reduce) 的声明。


八、代码组织 & 可维护性

优点

  1. CSS Module 组件隔离:每个组件有对应的 .module.css,样式作用域控制良好。

  2. 命名约定一致CSS 类名使用 scan- 前缀 + kebab-case,全局可识别。

问题

  1. CSS Module 堆叠模式过度耦合 (ScanTerminalDashboard.tsx:143-159)

    const scanTerminalRootClassName = clsx(
      styles.root,
      dashboardHomeStyles.root,
      dashboardMapStyles.root,
      // ... 共 22 个 CSS Module 的 .root 合并
    );
    

    单个组件 import 了 22 个 CSS Module,破坏了 CSS Module 的隔离优势。

  2. :global() 绕过了 CSS Module 的哈希:几乎所有规则都使用 :global(.class-name)class 名不会被哈希。CSS Module 降级为"命名约定"工具。

  3. 样式与逻辑耦合ScanTerminalDashboard.tsx 约 650 行,同时负责状态管理和渲染布局。

  4. 重复的 CSS 变量声明Dashboard.module.css 中重新声明了 --bg-primary 等本地变量,与 globals.css 的全局 token 形成冗余。


九、无障碍性

优点

  1. 部分元素有 aria-label(如 topbar 按钮、locale switch
  2. 主题切换按钮有 title 属性
  3. ProFeaturePaywall 使用了 role="dialog"aria-modal="true"

问题

  1. 键盘导航不足

    • 城市卡片没有 tabindexrole="button"
    • Tab 切换缺少 role="tablist"/role="tab"/aria-selected
    • 折叠按钮缺少 aria-expanded
  2. 焦点指示器不可见:自定义按钮(如 scan-theme-buttonscan-city-icon-button)没有 focus-visible 样式

  3. 颜色不是唯一的信息传达方式:风险等级、Market decision 的色彩编码缺少对应的文字标签或图标补充

  4. 没有 skip-to-content 链接

  5. 10-11px 小字体对视力障碍用户不友好


总结与优先级建议

高优先级(影响用户体验和可维护性)

# 问题 位置
1 !important 滥用导致浅色主题不可维护 ScanTerminalLightTheme.module.css
2 非标准 font-weight 值无效(760/850/950 等) 多个 CSS Module
3 Geist 字体声明但未加载 layout.tsx:35-37 / globals.css:55
4 键盘导航和 focus-visible 缺失 全局
5 断点碎片化(14 个断点值无体系) 所有响应式 CSS

中优先级(影响设计一致性)

# 问题 位置
6 22 个 CSS Module 堆叠耦合 ScanTerminalDashboard.tsx:143-159
7 Token 未充分利用(硬编码色值) 多个 CSS Module
8 @keyframes spin 重复定义 4 次 多个 CSS Module
9 Loading 状态设计不一致 DashboardMap vs ScanTerminalState
10 缺少 prefers-reduced-motion 支持 全局

低优先级(增强和优化)

# 问题 位置
11 "Fintech 3-Color" 实际只有 2 色 globals.css:25-27
12 Topbar 缺少 Logo/品牌标识 ScanTerminalDashboard.tsx
13 按钮视觉层级不够清晰 多个组件
14 Shadcn UI 组件存在但未被使用 components/ui/
15 --color-text-muted 对比度刚达标 globals.css:21

修复路线图建议

  1. Phase 1 — 修复 font-weight 无效值:全局搜索 font-weight: 760850860880900950,替换为 Inter 支持的 300-800 等效值
  2. Phase 2 — 重构浅色主题:将分散在 8+ 个文件中的浅色覆盖集中到一个 light-theme.css,使用 CSS 变量覆盖而非 !important
  3. Phase 3 — 补充无障碍:为 Tab/Button/Card 组件添加 ARIA 属性和 focus-visible 样式
  4. Phase 4 — 统一断点:定义 4-5 个标准断点(如 480/768/1024/1280/1440),逐步替换现有碎片化断点
  5. Phase 5 — 设计一致性:创建统一的 loading/empty/error 组件,清理未使用的 shadcn 组件

修复完成记录

修复日期:2026-05-10 | 变更范围:28 个文件,+693 / 2,198 行

高优先级 — 5/5 完成

# 问题 修复 涉及文件
1 !important 滥用 134 → 49(仅保留 Leaflet/图表所必需项),将 .root:global(.light) 替换为 html.light 以获得更高优先级 ScanTerminalLightTheme.module.cssglobals.css
2 非标准 font-weight 所有 760/850/860/880/950 等映射为 Inter 支持的 300800 13 个 CSS 文件
3 未加载 Geist --font-display 中移除,替换为 Inter globals.css
4 键盘 / 焦点可见 添加了全局 :focus-visible 轮廓环、跳过链接、Tab ARIArole="tablist"/role="tab"/aria-selected globals.csslayout.tsxScanFilterPanel.tsxScanTerminalDashboard.tsx
5 断点碎片化 18 → 10:合并 520/600/720/820/900/1020/1100/1240 → 640/768/960/1024/1280 9 个 CSS 文件

中优先级 — 5/5 完成

# 问题 修复 涉及文件
6 22 个 CSS Module 耦合 新建 scan-root-styles.ts 桶文件,将 22 个独立导入合并为 1 个预组合的 className scan-root-styles.ts(新建)、ScanTerminalDashboard.tsx
7 Token 使用不足 将主要颜色(#4DA3FF/#E6EDF3/#9FB2C7/#6B7A90/#6FB7FF)从 0 个变量引用替换为数百个 ScanTerminalCardScanTerminalListScanTerminalBoardScanTerminalOpportunityScanTerminalMobileScanTerminalDashboardHomeIntelligence
8 @keyframes spin 重复 4 次 移至 globals.cssloading-spin 去重 2 处;pulse-pending 移至全局 globals.css、4 个 CSS 文件
9 Loading 状态不一致 添加了 .scan-error-state.scan-retry-button.scan-empty-icon 用于统一状态呈现 ScanTerminalState.module.cssScanTerminalLightTheme.module.css
10 prefers-reduced-motion globals.css 中添加了全局动画/过渡禁用 globals.css

低优先级 — 5/5 完成

# 问题 修复 涉及文件
11 "3-Color" 仅 2 种颜色 将 accent-primary(blue) 和 accent-secondary(light-blue) 区分为不同颜色 globals.cssDashboard.module.css
12 Topbar 缺少 Logo 添加了 CSS 渐变品牌标记 ScanTerminalShell.module.cssScanTerminalDashboard.tsx
13 按钮层级不清晰 在 CSS 中添加了文档化的层级注释标题 ScanTerminalShell.module.css
14 Shadcn 未使用 已验证 6 个组件被 5 个文件使用(保留),更新了注释 globals.css
15 文字对比度不足 --color-text-muted#6B7A90 提升至 #7D8FA3 globals.css

其他修复

问题 修复
accent-green 类错误渲染为蓝色 ScanTerminal.module.css.scan-condition-value.accent-green#4DA3FF 修正为 #22C55E
Dashboard.module.css 重复的 CSS 变量 将本地 --bg-*/--accent-* 变量桥接至全局 token
死代码 移除 public/static/style.css1,459 行)和 public/legacy/index.html238 行)— 均未被引用
浅色主题 Token 基础设施 globals.css 中添加了 html.light CSS 自定义属性覆盖
品牌 Logo 浅色主题 ScanTerminalLightTheme.module.css 中添加了浅色主题 Logo 样式
空/错误状态浅色主题 ScanTerminalLightTheme.module.css 中添加了空/错误/重试的浅色覆盖

最终指标

指标 之前 之后
!important(可避免项) ~85 0
!important(必需项) ~49 49Leaflet 内联样式、图表 canvas 属性、减少动态效果)
硬编码调色板颜色 数百个 0(仅 globals.css 中的变量定义)
断点 18 个唯一值 10480/640/768/960/1024/1200/1280/1360/1440/1680
重复的 @keyframes 7 0
非标准 font-weight 全 13 个文件 0
CSS Module 导入 22 个独立导入 2(桶文件 + 共享)
死代码 1,697 行 0
净代码行数 1,505 行