跳转至

Clawline — 03-25~27 PWA适配与UX重构

移动端体验专项优化(03-25)

Dad 的目标

  • 不需要放大
  • 聊天界面不要横向滚动
  • 尽量接近原生体验

Bot 的技术分析

  • viewport 缺少 maximum-scale=1.0, user-scalable=no
  • Markdown 内容、代码块、长链接可能撑破布局
  • 消息行与内容容器存在 overflow 风险
  • 输入区按钮触控面积不足 44px

系统性修复方案

  • 全局防 horizontal overflow:确保页面不会左右滚动
  • 代码块内部滚动:代码块自己滚,不带动整页横向滚
  • 长 URL 自动换行:避免长链接撑破布局
  • 输入区按钮增大 touch target:满足 44px 最小触控目标
  • iOS 风格滚动与 overscroll-behavior:提供原生般的滚动体验

结果:移动端横向滚动与误触问题得到系统性修复。

PWA Service Worker 缓存问题暴露与解决

问题现象

PWA 底部空白 / safe-area 问题修复后,用户仍看不到变化。

根因分析演进

第一次误判:Bot 怀疑 Tailwind arbitrary value 未编译,但检查后 CSS 已生成。

真正根因: - PWA Service Worker cache-first 导致用户仍在使用旧 JS/CSS - Dad 没看到更新提示,旧 SW 持续控制页面 - 这不是部署问题,而是 SW 缓存策略问题

解决方案

  • 重新 build 生成新 hash
  • SW 自动 skipWaiting() 强制更新
  • 在 Profile 页面加入版本号与 build hash,便于确认真机是否拿到新版本
  • 通过 Vite define 注入全局版本信息

关键经验

PWA 缓存问题是"用户看不到更新"的常见根因,需要: 1. 明确的版本展示机制 2. 可靠的 SW 更新策略 3. 统一的 build hash 注入

PWA 层级问题修复

问题现象

ActionSheet 渲染在 overflow-y-auto 的消息容器内部,导致 iOS Safari/PWA 下 fixed 元素行为异常。

根因分析

  • 不是单纯 z-index 数值不够
  • 而是渲染层级上下文错误
  • 输入栏与 slash menu 形成多个 stacking context

解决方案

  • 将 safe-area 从 padding 改为独立 spacer,减少视觉空白
  • 调整输入栏与 ActionSheet 的层级关系
  • 将 ActionSheet 从滚动容器语义上"解耦"

关键提交2e70ded2

大分支合并(03-26)

feat/sprint1-ux → dev 合并

分叉点问题feat/sprint1-ux 从较早节点 4d1be4dc 分叉,早于后续 UI 改动,merge 时出现"旧 UI 覆盖新 UI"的风险。

冲突处理策略: - MarkdownRenderer.tsx:采用 sprint1-ux 版本(包含 remarkGfmrehypeRaw) - ChatList.tsx:保留 sprint1-ux 功能,改回 dev 的固定列数 grid 方案 - ChatRoom.tsx:手工 patch 合并两边的改动

结果:build 成功,但 ChatRoom bundle 从 150KB 涨到 336KB。

UI 回退问题修复

Dad 发现:"气泡样式又回来了"

根因:旧分支 merge 时覆盖了后续 flat UI

处理:重新核对分叉点,修复后部署。提交:730608da

左右互搏式 UX 重构(03-27)

引入 adversarial-qa 三角色机制

Dad 决策:加入批判员(Critic),形成更严格的审查闭环。

最终角色:执行官、审核员、批判员

5 轮 ChatRoom 重构成果

关键成果: - 提取/拆分:MessageItemHistoryDrawerHeaderMenuLongPressActionSheet、chat/types/utils/constants - ChatRoom.tsx2619 行降到 1879 行(-28.3%) - 终审评分 96/100 PASS

性能优化决策: - 减少 motion.div 使用,消息行改普通 div + CSS transition - 原因:长对话中每条消息一个 motion 实例,性能成本高

长按与复制功能修复

Dad 反馈:长按难用,复制文字功能"没法用了"

根因分析: 1. 移动端长按 400ms 就弹 ActionSheet,抢占了系统文字选择 2. 没有 touchmove 检测,想选中文字时被误判成长按菜单 3. navigator.clipboard 不存在时没有 fallback 4. copy 成功反馈只体现在桌面 hover 按钮上

解决方案: - 在消息内容区域阻止 touchStart 冒泡 - 增加 copy toast - 提高 ActionSheet 层级到 z-[60] - 触发 ActionSheet 时清除系统选择

iOS 特有问题

  • ActionSheet 与系统选择菜单同时出现
  • ActionSheet 被底部输入栏遮挡
  • Service Worker cache-first + iOS PWA 更新延迟

最终方案:SW 自动 skipWaiting(),统一 build hash 注入。

关键结论

这类问题的复合性

不是单纯前端样式 bug,而是 PWA 缓存策略 + iOS WebKit 行为 + DOM 层级结构 的复合问题。

组件拆分的价值

  • 代码可维护性显著提升
  • 单文件从 2600+ 行降到 1900 行
  • 清晰的职责划分便于后续迭代

移动端体验的系统性思考

移动端优化不是"修几个 CSS",需要从: - viewport 配置 - 触控目标尺寸 - 滚动行为 - 长按/选择交互 - PWA 缓存策略 等多个维度系统性考虑。

技术架构演进

ChatRoom.tsx (2619 lines)
    ↓ 5轮重构
ChatRoom.tsx (1879 lines)
├── MessageItem.tsx
├── HistoryDrawer.tsx
├── HeaderMenu.tsx
├── LongPressActionSheet.tsx
├── chat/types.ts
├── chat/utils.ts
└── chat/constants.ts