news 2026/9/11 6:29:03

Qwen Code WebShell 移动端空会话 Composer 底部锚定:760px 断点布局修复与 E2E 验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Qwen Code WebShell 移动端空会话 Composer 底部锚定:760px 断点布局修复与 E2E 验证

Qwen Code WebShell 移动端空会话 Composer 底部锚定:760px 断点布局修复与 E2E 验证

【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code

导读

本文围绕 Qwen Code WebShell 在窄视口(≤760px)下的空会话(new-chat)布局展开,聚焦「移动端 composer 底部锚定(mobile composer-bottom)」这一布局路径:介绍断点激活条件、mobileWelcomeFooterMiddle等宿主 Props 的语义、CSS 修复方案(绝对定位 footer 对齐聊天面板底部),并梳理仓库中对应的 Chromium E2E 测试矩阵与可复现命令。读完本文,你将掌握该布局的触发条件、修复前后差异、各变体(有无欢迎页脚、自定义页脚)的渲染行为,以及如何在本地用 Playwright 复现与验证这一缺陷。

场景:窄视口下空会话的 Composer 布局

在 WebShell 中,当用户尚未打开任何会话(空会话态)时,聊天面板会渲染欢迎头(welcome header)与欢迎脚(welcome footer),并竖直居中显示。在桌面宽度下,composer 作为聊天面板的常规 flex 子项参与流式排版;但在移动端窄视口下,WebShell 切换为mobile composer-bottom 布局:composer 需要「贴住」聊天面板底部,而不是悬浮在内容流的某个位置。

原设计文档(2026-08-05-webshell-mobile-composer-bottom.md)给出的复现场景是:

在无会话状态下打开 composer-layout 测试挂载(harness),启用mobileWelcomeFooterMiddle以及欢迎头/欢迎脚渲染器;在760px 视口宽度下,空聊天面板使用 mobile composer-bottom 布局;随后把宽度调整到 761px 再调回 760px。

这一场景同时涵盖了布局的激活断点切换恢复三个维度,是验证该路径是否健壮的最小用例。

修复前的缺陷:419px 的页脚到面板底部间距

在 CSS 修复之前,内部 Chromium 挂载在760×900视口下实测到:composer 页脚底部(footer bottom)与聊天面板底部(chat pane bottom)之间存在419px 的间距

这意味着窄屏用户打开 WebShell 时,输入框并没有稳稳地贴在屏幕/面板底部,而是悬浮在面板中部偏下的位置——视觉上「悬空」,与底部工具栏、安全区之间出现大段空白,体验割裂。

缺陷的根源在于:空会话态为了竖直居中欢迎内容,聊天面板使用了居中布局,而移动断点下的 composer 仍以流式元素参与排版,没有获得「底部锚定」的定位上下文。修复的目标非常明确:在 ≤760px 时让 composer 页脚绝对定位并贴住聊天面板底部

断点与锚定机制:760px 的 CSS 实现

移动布局的开关是媒体查询@media (max-width: 760px),实现在 packages/web-shell/client/App.module.css 中。核心规则如下:

@media (max-width: 760px) { .appChatEmpty .chatPaneWithMobileComposerBottom { position: relative; overflow: hidden; } .appChatEmpty .chatViewWithMobileComposerBottom .footer { position: absolute; right: 0; bottom: 0; left: 0; margin-top: 0; } }

关键点逐一拆解:

  • position: relative建立定位上下文:聊天面板(.chatPaneWithMobileComposerBottom)在空会话态下成为包含块,同时overflow: hidden防止绝对定位的页脚溢出面板。
  • position: absolute; bottom: 0完成锚定:composer 页脚(.footer)被从文档流中取出,直接贴住面板底部,right/left: 0保证横向铺满。
  • 断点即开关:在 761px 及以上,该规则不生效,页脚回到流式布局(position: relative);宽度回调到 760px 时,底部锚定自动恢复——这正是文档场景中「761px→760px 往返」要验证的行为。

为保证空会话态下该定位生效,CSS 还配套了两条前置规则(App.module.css):

.appChatEmpty .chatViewWrap { flex: 0 0 auto; overflow: visible; }

注释解释了原因:空会话态通过.appChatEmpty .chatPane { justify-content: center }实现欢迎内容竖直居中,为此聊天视图包裹层必须收缩到内容尺寸(flex: 0 0 auto)而不是填满面板,居中定位才能成立;页脚则脱离该包裹层,独立锚定到面板底部。

触发布局的宿主 Props

mobile composer-bottom 布局并非默认启用,而是由宿主(宿主应用通过 Props 定制 WebShell)显式声明。三个关键 Props 定义在 packages/web-shell/client/App.tsx:

Props类型作用
renderWelcomeHeaderWelcomeHeaderRenderer空会话态欢迎头的自定义渲染器(接收 version、cwd、model、mode 等参数)
renderWelcomeFooterWelcomeFooterRenderer空会话态显示在 composer 下方的自定义渲染器
mobileWelcomeFooterMiddlebooleantrue时,在移动端空会话态把renderWelcomeFooter渲染到「欢迎头与 composer 之间」,移动 CSS 重排依赖该开关

三者的联动关系是:mobileWelcomeFooterMiddle要求同时提供renderWelcomeFooter,否则移动端 CSS 重排不会生效(见 App.tsx 中的 JSDoc 注释)。

组合变体:display: contents与页脚排序

当同时存在欢迎脚与自定义页脚(renderFooter)时,移动断点下的渲染顺序需要显式控制。CSS 中通过display: contentsorder实现(App.module.css):

.appChatEmpty .chatViewWithWelcomeMiddle .footerWithCustomFooter { display: contents; } .appChatEmpty .chatViewWithWelcomeMiddle .footerWithCustomFooter .composer { order: 2; width: min(100%, var(--chat-shell-width)); margin: 0 auto; padding-right: 20px; padding-left: 20px; } .appChatEmpty .chatViewWithWelcomeMiddle .mobileWelcomeFooterMiddle { display: flex; flex: 0 0 auto; align-items: flex-start; justify-content: center; width: min(100%, var(--chat-shell-width)); margin: 0 auto; padding-right: 20px; padding-left: 20px; } .appChatEmpty .chatViewWithWelcomeMiddle .customFooter { order: 1; display: flex; flex: 0 0 auto; ... }

含义拆解:

  • display: contents:自定义页脚变体下,页脚容器自身不产生盒模型,其子元素(composer、欢迎脚、自定义页脚)直接参与父级 flex 排布,这保证了绝对定位的底部面板(如状态面板)仍能以上方内容为包含块正确锚定——对应 CSS 中针对.chatViewWithCustomFooterposition: relative兜底规则(App.module.css)。
  • order控制纵向顺序:自定义页脚(order: 1)在欢迎脚之上,composer(order: 2)沉底,欢迎头则保持在最上方——对应文档场景中「welcome header 保持在 composer 上方」的检查项。
  • 居中与宽度约束:composer 与欢迎脚都受--chat-shell-width约束并水平居中,与桌面端视觉一致。

与移动输入后端的配合

移动 composer-bottom 布局同样适用于触摸设备上的 textarea 输入后端:当宿主以mobile-chromium项目(Pixel 7 模拟:touch、coarse pointer、无 hover)运行时,composer 渲染为纯 textarea 而非 CodeMirror。移动端空会话锚定在 textarea 后端同样有专门的 E2E 覆盖(见下文测试矩阵),保证窄屏触控设备的锚定与输入可用性不因输入组件切换而退化。

Chromium E2E 验证矩阵

仓库围绕该布局提供了一组 Playwright 测试,是文档中「可执行基线」的实体。主测试文件为 packages/web-shell/client/e2e/web-shell.smoke.spec.ts,共 4 个相关用例:

测试用例关注点
anchors the empty mobile composer to the chat pane across the breakpoint @smoke(L1602)760px 锚定 → 761px 断点停用 → 调回 760px 恢复锚定,并验证 composer 可键入
anchors the empty mobile composer without a welcome footer @smoke(L1649)无欢迎脚(renderWelcomeFooter缺省)时仍正确锚定
keeps the bottom status panel visible in the custom footer mobile welcome variant @smoke(L1669)自定义页脚变体中,底部状态面板保持在聊天面板范围内
anchors the empty mobile composer with a custom footer but no welcome footer @smoke(L1705)自定义页脚 + 无欢迎脚的组合变体

另外,textarea 后端锚定由 packages/web-shell/client/e2e/web-shell.composer.mobile.spec.ts 中的anchors the empty mobile composer with the textarea backend覆盖(在mobile-chromium项目下运行,触摸点按输入并断言 textarea 值)。

锚定的量化断言

expectEmptyMobileComposerAnchored(packages/web-shell/client/e2e/utils/emptyMobileComposer.ts)把「锚定正确」翻译为一组可判定的几何与样式断言:

expect(layout.footerPosition).toBe('absolute'); expect(Math.abs(layout.footerBottom - layout.chatPaneBottom)).toBeLessThanOrEqual(1); expect(layout.chatViewPosition).toBe('static'); expect(layout.chatViewIsPaneFlexItem).toBe(true); expect(layout.chatViewZIndex).toBe('auto'); expect(layout.footerAnchoredToChatPane).toBe(true);

要点:

  • 页脚底与面板底偏差 ≤1px:这是「贴住底部」的量化标准,419px 的缺陷在该断言下会直接失败;
  • 页脚offsetParent必须是聊天面板:验证position: relative包含块关系确实建立;
  • 聊天视图position: staticz-index: auto:确保欢迎内容不被浮层干扰,处于正常层叠上下文。

复现与运行命令

文档给出了可直接执行的复现命令(--grep精确匹配锚定用例):

npx playwright test --config packages/web-shell/playwright.config.ts packages/web-shell/client/e2e/web-shell.smoke.spec.ts --grep 'anchors the empty mobile composer'

该命令同时覆盖across the breakpointwithout a welcome footer两个用例。修复后上游聚焦运行结果为3 passed(含另一处锚定相关用例)。移动触控后端用例则通过mobile-chromiumproject 运行,可配合 Playwright 的--project参数执行。

测试挂载(harness)如何构造场景

场景由 packages/web-shell/client/e2e/composer-layout-harness.tsx 提供:通过 URL 查询参数emptyMobileWelcome=true进入空欢迎态,并注入mobileWelcomeFooterMiddle: truerenderWelcomeHeaderrenderWelcomeFooterwelcomeFooter=false时省略后者),以及customFooter=true时注入renderFooterbottomStatusItems。这印证了上文 Props 语义——布局完全由宿主 Props 驱动,因此同一 harness 可枚举出「有/无欢迎脚 × 有/无自定义页脚」的组合矩阵。

关于 CLI 基线不适用性的说明

文档特别指出:对该 host-only 布局路径,针对全局qwenCLI 的基线 dry-run不适用——CLI 不渲染 WebShell DOM,也不暴露mobileWelcomeFooterMiddlerenderWelcomeHeaderrenderWelcomeFooter这些宿主 Props,因此无法触发该布局。可执行的基线就是上文基于真实 Chromium 的 composer-layout 挂载:它在 CSS 修复前以「页脚到面板底部 419px 间距」复现了缺陷。这一说明对读者有实用价值:验证该路径无需也无法通过 CLI 完成,请直接跑 Playwright 用例

修复效果小结

综合设计文档与仓库源码,本次修复达成的可验证目标包括:

  1. 底部锚定:≤760px 时 composer 页脚以绝对定位贴住聊天面板底部(偏差 ≤1px 的量化断言);
  2. 欢迎内容层级正确:欢迎头位于 composer 上方,欢迎脚(mobileWelcomeFooterMiddle模式下)位于欢迎头与 composer 之间,不遮挡前景、不捕获指针事件;
  3. 断点往返稳定:761px 时移动绝对定位规则停用,回调 760px 后底部锚定自动恢复;
  4. 输入可用:锚定状态下 composer 可正常键入、触控设备使用 textarea 后端、草稿可清空而不提交;
  5. 组合变体覆盖:有无欢迎脚、有无自定义页脚、有无状态面板的矩阵均有用例保障,且display: contents变体的测量限制(无盒模型、断言必须拒绝而非误报)在测试中被显式处理(web-shell.smoke.spec.ts)。

对需要定制 WebShell 空会话欢迎区的宿主开发者而言,本文涉及的三个 Props 与 760px 断点规则构成了完整的接入契约;对维护者而言,上述 Playwright 用例则是该布局路径的回归防线,可随时在本地以文档中的命令复现验证。

【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 6:28:46

WorkBuddy开放平台个人开发者实战:从零构建Agent应用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 6:28:35

MATLAB控制系统建模与MAD流程实战指南

1. 控制系统建模仿真入门:MAD流程与MATLAB基础 控制系统设计就像搭积木,MAD(Modeling-Analysis-Design)流程就是我们的搭建手册。这个方法论把复杂的设计过程分解为三个可操作的阶段:先建立数学模型(Modeli…

作者头像 李华
网站建设 2026/9/11 6:27:00

新手如何克服写作恐惧并完成第一篇文章

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 6:25:16

西门子S7-1200变频恒压供水系统设计与PID控制

1. 西门子S7-1200变频恒压供水系统概述在工业自动化领域,恒压供水系统是典型的闭环控制应用场景。我最近完成的一个项目就是基于西门子S7-1200 PLC的变频恒压供水系统设计,这个系统通过PID算法精确控制水泵转速,实现了管网压力的稳定输出。相…

作者头像 李华