Sfoglia il codice sorgente

style(mobile): 首页元素按用户方案收紧,给底部内容留出空间

真机上夸克/vivo 的建议词被固定输入框遮住(夸克遮 1 段、vivo 遮 2 段)。按用户给出的
方案收紧首页:

- 顶栏 64px → 52px
- logo 130×88 + 下边距 41px → 96×65 + 20px
- 大标题 28px → 22px,并用 clamp(18px,5.6vw,22px) 让窄屏继续收;加 white-space: nowrap
  让它恒定单行(原先 13 个字在窄屏放不下会折两行)
- 欢迎区 gap 7px → 6px;介绍文案行高 1.6 → 1.5
- 建议词区 padding-top 28px → 18px、gap 12px → 10px

估算内容总高 ~723px → ~601px(-17%)。

⚠️ 未解决的:手机可视高度(去掉地址栏)通常 560~600px,601 仍偏紧,小屏可能还是差一点。
根因未动 —— .home-fixed-input 仍是 position:fixed 悬浮、不占文档流,而给它的预留是写死的
padding-bottom:180px,与输入框实际高度无关。若仍被遮,下一步需改成「输入框占位」
(flex 子项 + .mobile-main { min-height: 0 }),那样剩余高度由浏览器算,与字体/内核无关。

验证:npm run build 通过;新值已逐项核对进源码。⚠️ 未在真机验证。

Co-Authored-By: Claude Code <noreply@anthropic.com>
gongtianxiao 2 giorni fa
parent
commit
9ccf5360ef

+ 27 - 0
harness/docs/exec-plans/tech-debt-tracker.md

@@ -68,6 +68,33 @@
 - **一个低成本的前置动作(尚未做)**:把 `index.html` 里写死的 `globalThis.isXF = false`
   **改成环境变量开关** —— 这样万一厂商出问题,改配置就能切到讯飞分支,不必改代码重新发版。
 
+### 7. 移动端真机样式问题:没有兼容基线,且布局依赖 JS 测量
+
+- **是什么**:用户反馈**真机**上(F12 模拟正常)①首页展示不全 ②思考过程文案超出屏幕
+  ③**不同浏览器问题还不一样**。排查后确认三个相互独立的根因:
+  1. **`height: 100dvh` 没有 `100vh` 兜底**(`BusinessAssistantMobile.vue`)——
+     `dvh` 是较新的单位(Chrome 108+ / Safari 15.4+),国产浏览器内核多基于更老的版本
+     → 该声明被整条丢弃 → 容器高度塌陷,而外层是 `overflow: hidden` → **内容被裁掉**
+  2. **没有 `text-size-adjust: 100%`** —— 移动端浏览器会按各自策略自动放大文字,
+     各家不同 → 同一份文案在不同手机上长度不同(也是"不同浏览器不一样"的直接来源)
+  3. **思考过程卡片的样式靠 JS 测量 + `width: max-content` 决定**「单行省略 vs 换行」:
+     `updateMaxWidthReached()` 用 `getBoundingClientRect()` 比卡片与父容器宽度。
+     而字体首选 `"HarmonyOS Sans SC"`(**手机多无此字体 → 回退到系统字体**)→ **字宽不同**
+     → 测量结果不同 → 该换行时判成"没撑满" → 单行 `nowrap` 撑出屏幕
+- **为什么先欠着**:**需用户提供信息/确认改法**(见下),且其中一条会改变观感
+- **欠着会怎样**:移动端(本项目的主要使用场景)体验不稳定,且**换台手机就可能变样**
+- **该还的条件**:
+  1. 用户提供**具体浏览器与版本**、以及能否**真机远程调试**(Android 用 `chrome://inspect`
+     最省事)—— 没有这个只能猜
+  2. 方案 A(低风险、可立刻做):`dvh` 加 `vh` 兜底、全局 `text-size-adjust: 100%`、
+     给 flex 链补 `min-width: 0`
+  3. 方案 B(**建议做**,但要用户确认观感变化):**去掉「按宽度切样式」这套测量**,
+     改为纯 CSS —— 标题恒定单行省略、正文恒定可换行,删掉 `is-max-width-reached`
+     与 `width: max-content`。现在这套**先天不稳定**(字体/时机/内核都会影响测量)
+  4. 方案 C(机制):定**浏览器兼容基线** + 加 `browserslist`;
+     项目当前**没有任何 browserslist / postcss 降级配置**,而代码里用了
+     `dvh`(4) / `gap`(151) / `inset`(22) / `backdrop-filter`(24) 等较新特性
+
 ## 已还
 
 (还清后从上面移到此处,保留一行说明怎么还的,便于追溯)

+ 33 - 0
harness/progress.md

@@ -2194,3 +2194,36 @@
     换自建服务时只改配置;**替换需要提供的清单**已在本会话给出(OSS 凭据 + 一个签名服务 + 文件访问前缀)
 - **下一步最佳动作**:功能清单里已无 in_progress;可选方向见 Session 031 列的优先级
 
+## Session 055
+
+- **日期**:2026-09-18
+- **本轮背景**:用户反馈移动端真机问题(夸克:第 3 段建议词被输入框遮住;vivo:后两段被遮),
+  并给出自己的方案:**顶栏矮一点、图片小一点、标题字号小且不换行、按需合理调整**
+- **已完成**(按用户方案,`BusinessAssistantMobile.vue` 首页):
+
+  | 元素 | 改前 | 改后 |
+  |---|---|---|
+  | 顶栏 `.mobile-header` | 64px | **52px** |
+  | logo `.overlay-icon`(含下边距) | 130×88 + 41 | **96×65 + 20** |
+  | 大标题 `.heading` | 28px(13 字放不下会折两行) | **22px + `clamp(18px,5.6vw,22px)` + `nowrap`**(恒定单行) |
+  | 欢迎区 gap | 7px | 6px |
+  | 介绍文案行高 | 1.6 | 1.5 |
+  | 建议词区 | padding 28 / gap 12 | **padding 18 / gap 10** |
+
+  - 标题字号用「先固定 22px、再 `clamp` 覆盖」的写法:**老内核拿到 22px(窄屏也放得下),
+    新内核按屏宽继续收** —— 目的是保证恒定单行
+  - 估算内容总高 **~723px → ~601px(−17%)**
+- **⚠️ 未解决(本轮不假装解决)**:手机可视高度(去掉地址栏)通常 560~600px,
+  **601 仍很紧,小屏可能还是差一点**。**根因没动**:`.home-fixed-input` 仍是 `position: fixed`
+  悬浮、不占文档流,而给它预留的是**写死的 `padding-bottom: 180px`**,与输入框实际高度无关
+  —— 字体一放大、输入框一换行,180px 就不够
+- **运行过的验证**:`npm run build` 通过;逐项核对新值已落进源码
+- **已记录证据**:本文件 Session 055;技术债第 7 条;上面的量化表
+- **更新过的文件或工件**:`src/components/BusinessAssistantMobile.vue`、本文件、技术债清单
+- **已知风险或未解决问题**:
+  - ⚠️ **未在真机验证**:需用户在夸克 / vivo 上再看一次
+  - ⚠️ 若仍被遮,**下一步只能上「输入框占位」**(去掉 `position: fixed`,改成
+    `.ba-mobile-container` 的 flex 子项 + `.mobile-main { min-height: 0 }`)——
+    那样剩余高度是**浏览器算出来的**,与字体/内核无关,数学上不会再遮
+- **下一步最佳动作**:用户真机确认;若仍遮则做「输入框占位」
+

+ 14 - 10
src/components/BusinessAssistantMobile.vue

@@ -1626,7 +1626,7 @@ const confirmDeleteSession = () => {
 }
 
 .mobile-header {
-  height: 64px;
+  height: 52px;
   flex-shrink: 0;
   display: flex;
   align-items: center;
@@ -1788,29 +1788,33 @@ const confirmDeleteSession = () => {
   display: flex;
   flex-direction: column;
   align-items: center;
-  gap: 7px;
+  gap: 6px;
   margin: 0;
   text-align: center;
 }
 
 .overlay-icon {
-  width: 130px;
-  height: 88px;
+  width: 96px;
+  height: 65px;
   border-radius: 999px;
   display: flex;
   align-items: center;
   justify-content: center;
-  margin-bottom: 41px;
+  margin-bottom: 20px;
 }
 
 .heading {
   margin: 0;
   color: #141b2b;
-  font-size: 28px;
+  /* 先给老内核一个固定值(窄屏也放得下),再用 clamp 让更窄的屏继续收一点。
+     目的:这行字**恒定单行**不换行 */
+  font-size: 22px;
+  font-size: clamp(18px, 5.6vw, 22px);
   font-weight: 500;
   line-height: 1.2;
   letter-spacing: -0.64px;
-  margin-bottom: 17px;
+  margin-bottom: 12px;
+  white-space: nowrap;
 }
 
 .desc {
@@ -1818,7 +1822,7 @@ const confirmDeleteSession = () => {
   color: #464555;
   font-size: 14px;
   font-weight: 500;
-  line-height: 1.6;
+  line-height: 1.5;
 }
 
 .chat-input-area {
@@ -1864,9 +1868,9 @@ const confirmDeleteSession = () => {
   display: flex;
   flex-direction: column;
   align-items: center;
-  gap: 12px;
+  gap: 10px;
   width: 100%;
-  padding: 28px 40px 0;
+  padding: 18px 32px 0;
 }
 
 .chip {